SWAGOLX.EXE (c) 1993 GDSOFT ALL RIGHTS RESERVED 00031 SORTING ROUTINES 1 05-28-9313:57ALL SWAG SUPPORT TEAM ALPHAREC.PAS IMPORT 7 { Alphabetic Rec Sort }ππProcedure SortIt(Key : Byte);πVarπ I, J : Byte;ππProcedure Swapper;πVarπ T : Member;ππbeginπ T := Memrec[I];π MemRec[I] := MemRec[J];π MemRec[J] := T;πend;ππbeginπ For I := 1 to MaxMem - 1 DOπ For J := I To MaxMem do beginπ Case Key OFπ 1 : if MemRec[I].Firstname < MemRec[J].FirstName then Swapper;π 2 : if MemRec[I].LastName < MemRec[J].LastName then Swapper;π 3 : if MemRec[I].Points < MemRec[J].Points then Swapper;π end;πend;ππ{πAnother Alternative would be to do as C does, make a Generic Sort routineπwhere you pass it a Function that returns > 0 if Record1 is greater thanπRecord2, < 0 if Record1 is Less than Record2, and 0 if they are the same.π}π 2 05-28-9313:57ALL SWAG SUPPORT TEAM ANAGRAM1.PAS IMPORT 196 (* Start of PART 1 of 7 *)ππ(***********************************************************************π Contest 3 Entry : Anagram Sort by Guy McLoughlinπ Compiler : Borland Pascal 7.0π***********************************************************************)ππ {.$DEFINE DebugMode}ππ {$IFDEF DebugMode}π {$A+,B-,D+,E-,F-,G+,I+,L+,N-,O-,P-,Q+,R+,S+,T+,V+,X-}π {$ELSE}π {$A+,B-,D-,E-,F-,G+,I-,L-,N-,O-,P-,Q-,R-,S+,T-,V-,X-}π {$endIF}ππ {$M 16384,374784,655360}ππProgram Anagram_Sort;ππConstπ co_MaxWord = 2500;π co_MaxSize = 65519;π co_SafeSize = 64500;ππTypeπ Char_12 = Array[1..12] of Char;ππ st_4 = String[4];π st_10 = String[10];π st_80 = String[80];ππ byar_26 = Array[97..122] of Byte;ππ po_Buff = ^byar_Buffer;π byar_Buffer = Array[1..co_MaxSize] of Byte;ππ porc_Word = ^rc_Word;π rc_Word = Recordπ wo_Pos : Word;π ar_LtrChk : Char_12;π st_Word : st_10π end;ππ poar_Word = Array[0..co_MaxWord] of porc_Word;ππ porc_AnaGroup = ^rc_AnaGroup;π rc_AnaGroup = Recordπ wo_Pos : Word;π st_Group : st_80π end;ππ poar_AnaGroup = Array[0..co_MaxWord] of porc_AnaGroup;π poar_Generic = Array[0..co_MaxWord] of Pointer;ππ (***** Check For I/O errors. *)π (* *)π Procedure CheckIOerror;π Varπ by_Error : Byte;π beginπ by_Error := ioresult;π if (by_Error <> 0) thenπ beginπ Writeln('Input/Output error = ', by_Error);π haltπ endπ end; (* CheckIOerror. *)ππ (***** Display HEAP error message. *)π (* *)π Procedure HeapError;π beginπ Writeln('Insuficient free HEAP memory');π haltπ end; (* HeapError. *)ππTypeπ Item = Pointer;π ar_Item = poar_Generic;π CompFunc = Function(Var Item1, Item2 : Item) : Boolean;ππ (* end of PART 1 of 7 *)π (* Start of PART 2 of 7 *)ππ (***** QuickSort routine. *)π (* *)π Procedure QuickSort({update} Var ar_Data : ar_Item;π {input } wo_Left,π wo_Right : Word;π LessThan : CompFunc);π Varπ Pivot,π TempItem : Item;π wo_Index1,π wo_Index2 : Word;π beginπ wo_Index1 := wo_Left;π wo_Index2 := wo_Right;π Pivot := ar_Data[(wo_Left + wo_Right) div 2];π Repeatπ While LessThan(ar_Data[wo_Index1], Pivot) doπ inc(wo_Index1);π While LessThan(Pivot, ar_Data[wo_Index2]) doπ dec(wo_Index2);π if (wo_Index1 <= wo_Index2) thenπ beginπ TempItem := ar_Data[wo_Index1];π ar_Data[wo_Index1] := ar_Data[wo_Index2];π ar_Data[wo_Index2] := TempItem;π inc(wo_Index1);π dec(wo_Index2)π endπ Until (wo_Index1 > wo_Index2);π if (wo_Left < wo_Index2) thenπ QuickSort(ar_Data, wo_Left, wo_Index2, LessThan);π if (wo_Index1 < wo_Right) thenπ QuickSort(ar_Data, wo_Index1, wo_Right, LessThan)π end; (* QuickSort. *)ππ (***** Sort Function to check if anagram-Word's are in sorted order *)π (* *)π Function AlphaSort(Var Item1, Item2 : Item) : Boolean; Far;π beginπ AlphaSort := (porc_Word(Item1)^.st_Word < porc_Word(Item2)^.st_Word)π end; (* AlphaSort. *)ππ (***** Sort Function to check: *)π (* *)π (* 1 - If anagram-Words are sorted by length. *)π (* 2 - If anagram-Words are sorted by anagram-group. *)π (* 3- If anagram-Words are sorted alphabeticly. *)π (* *)π Function Sort1(Var Item1, Item2 : Item) : Boolean; Far;π beginπ if (porc_Word(Item1)^.st_Word[0] <>π porc_Word(Item2)^.st_Word[0]) thenπ Sort1 := (porc_Word(Item1)^.st_Word[0] <π porc_Word(Item2)^.st_Word[0])π elseπ if (porc_Word(Item1)^.ar_LtrChk <>π porc_Word(Item2)^.ar_LtrChk) thenπ Sort1 := (porc_Word(Item1)^.ar_LtrChk <π porc_Word(Item2)^.ar_LtrChk)π elseπ Sort1 := (porc_Word(Item1)^.wo_Pos < porc_Word(Item2)^.wo_Pos)π end; (* Sort1. *)ππ (***** Sort Function to check: *)π (* *)π (* If anagram-group Strings are sorted alphabeticly. *)π (* *)π Function Sort2(Var Item1, Item2 : Item) : Boolean; Far;π beginπ Sort2 := (porc_AnaGroup(Item1)^.wo_Pos <π porc_AnaGroup(Item2)^.wo_Pos)π end; (* Sort2. *)ππ (* end of PART 2 of 7 *)π (* Start of PART 3 of 7 *)ππ (***** Check if the anagram-Word table is in sorted order. *)π (* *)π Function TableSorted({input } Var ar_Data : poar_Word;π wo_Left,π wo_Right : Word) : {output} Boolean;π Varπ wo_Index : Word;π beginπ (* Set Function result to True. *)π TableSorted := True;ππ (* Loop through all but the last Word in the anagram- *)π (* Word "table". *)π For wo_Index := wo_Left to pred(wo_Right) doπ (* Check if the current and next anagram-Words are not *)π (* sorted. *)π if (ar_Data[wo_Index]^.st_Word >π ar_Data[succ(wo_Index)]^.st_Word) thenπ beginπ (* Set Function result to False, and break the "for" *)π (* loop. *)π TableSorted := False;π breakπ endπ end; (* TableSorted. *)ππ (***** Pack bits 0,1,2 of each Byte in 26 Byte Array into 10 Chars. *)π (* *)π Procedure PackBits({input } Var byar_Temp : byar_26;π {output} Var Char_Temp : Char_12);π beginπ Char_Temp[ 1] := chr((byar_Temp[ 97] and $7) shl 5 +π (byar_Temp[ 98] and $7) shl 2 +π (byar_Temp[ 99] and $6) shr 1);π Char_Temp[ 2] := chr((byar_Temp[ 99] and $1) shl 7 +π (byar_Temp[100] and $7) shl 4 +π (byar_Temp[101] and $7) shl 1 +π (byar_Temp[102] and $4) shr 2);π Char_Temp[ 3] := chr((byar_Temp[102] and $3) shl 6 +π (byar_Temp[103] and $7) shl 3 +π (byar_Temp[104] and $7));π Char_Temp[ 4] := chr((byar_Temp[105] and $7) shl 5 +π (byar_Temp[106] and $7) shl 2 +π (byar_Temp[107] and $6) shr 1);π Char_Temp[ 5] := chr((byar_Temp[107] and $1) shl 7 +π (byar_Temp[108] and $7) shl 4 +π (byar_Temp[109] and $7) shl 1 +π (byar_Temp[110] and $4) shr 2);π Char_Temp[ 6] := chr((byar_Temp[110] and $3) shl 6 +π (byar_Temp[111] and $7) shl 3 +π (byar_Temp[112] and $7));π Char_Temp[ 7] := chr((byar_Temp[113] and $7) shl 5 +π (byar_Temp[114] and $7) shl 2 +π (byar_Temp[115] and $6) shr 1);π Char_Temp[ 8] := chr((byar_Temp[115] and $1) shl 7 +π (byar_Temp[116] and $7) shl 4 +π (byar_Temp[117] and $7) shl 1 +π (byar_Temp[118] and $4) shr 2);π Char_Temp[ 9] := chr((byar_Temp[118] and $3) shl 6 +π (byar_Temp[119] and $7) shl 3 +π (byar_Temp[120] and $7));π Char_Temp[10] := chr((byar_Temp[121] and $7) shl 5 +π (byar_Temp[122] and $7) shl 2)π end; (* PackBits. *)ππVarπ po_Buffer : po_Buff;ππ by_Index,π by_LastAnagram,π by_CurrentWord : Byte;ππ wo_Index,π wo_ReadIndex,π wo_TableIndex,π wo_BufferIndex,π wo_CurrentIndex : Word;ππ (* end of PART 3 of 7 *)π (* Start of PART 4 of 7 *)ππ st_Temp : st_4;ππ byar_LtrChk : byar_26;ππ fi_Temp : File;ππ rcar_Table : poar_Word;ππ rcar_Groups : poar_AnaGroup;πππ (* Main Program execution block. *)πbeginπ (* If there is sufficient room, allocate the main data- *)π (* buffer on the HEAP. *)π if (maxavail > co_MaxSize) thenπ new(po_Buffer)π elseπ (* Else, inform user of insufficient HEAP memory, and *)π (* halt the Program. *)π HeapError;ππ (* Clear the data-buffer. *)π fillChar(po_Buffer^, co_MaxSize, 0);ππ (* Initialize counter Variable. *)π wo_Index := 0;ππ (* While the counter is less than co_MaxWord do... *)π While (co_MaxWord > wo_Index) doππ (* If there is sufficient memory, allocate another *)π (* anagram-Word Record on the HEAP. *)π if (maxavail > sizeof(rc_Word)) thenπ beginπ inc(wo_Index);π new(rcar_Table[wo_Index]);π fillChar(rcar_Table[wo_Index]^, sizeof(rc_Word), 0);π endπ elseπ (* Else, inform user of insufficient HEAP memory, and *)π (* halt the Program. *)π HeapError;ππ (* Initialize counter Variable. *)π wo_Index := 0;ππ (* While the counter is less than co_MaxWord do... *)π While (co_MaxWord > wo_Index) doππ (* If there is sufficient memory, allocate another *)π (* anagram-group String on the HEAP. *)π if (maxavail > sizeof(rc_AnaGroup)) thenπ beginπ inc(wo_Index);π new(rcar_Groups[wo_Index]);π fillChar(rcar_Groups[wo_Index]^, sizeof(rc_AnaGroup), 32);π endπ elseπ (* Else, inform user of insufficient HEAP memory, and *)π (* halt the Program. *)π HeapError;ππ (* Attempt to open File containing the anagram-Words. *)π assign(fi_Temp, 'WordLIST.DAT');ππ (* Set Filemode to "read-only". *)π Filemode := 0;π {$I-}π reset(fi_Temp, 1);π {$I+}π (* Check For I/O errors. *)π if (ioresult <> 0) thenπ beginπ Writeln('Error opening anagram data File ---> WordLIST.DAT');π haltπ end;π (* Read-in the entire anagram list into the data-buffer *)π blockread(fi_Temp, po_Buffer^, co_MaxSize, wo_ReadIndex);ππ (* end of PART 4 of 7 *)π (* Start of PART 5 of 7 *)ππ (* Check For I/O errors. *)π CheckIOerror;ππ close(fi_Temp);ππ (* Check For I/O errors. *)π CheckIOerror;ππ (* Initialize index Variables. *)π wo_TableIndex := 0;π wo_BufferIndex := 0;ππ (* Repeat...Until all data in the data-buffer has been *)π (* processed. *)π Repeatππ (* Repeat...Until a valid anagram-Word Character has *)π (* been found, or the complete data-buffer has been *)π (* processed. *)π Repeatπ inc(wo_BufferIndex)π Until ((po_Buffer^[wo_BufferIndex] > 96)π and (po_Buffer^[wo_BufferIndex] < 123))π or (wo_BufferIndex > wo_ReadIndex);ππ (* If the complete data-buffer has been processed then *)π (* break the Repeat...Until loop. *)π if (wo_BufferIndex > wo_ReadIndex) thenπ break;ππ (* Advance the anagram-Word "table" index. *)π inc(wo_TableIndex);ππ (* Clear the "letter check" Byte-Array Variable. *)π fillChar(byar_LtrChk, sizeof(byar_26), 0);ππ (* Repeat...Until not an anagram-Word Character, or *)π (* complete data-buffer has been processed. *)π Repeatππ (* With the current anagram-Word Record do... *)π With rcar_Table[wo_TableIndex]^ doπ beginπ (* Record the number of each alphabetical Character in *)π (* the anagram-Word. *)π inc(byar_LtrChk[po_Buffer^[wo_BufferIndex]]);ππ (* Advance the String length-Character. *)π inc(st_Word[0]);ππ (* Add the current anagram-Word Character to anagram- *)π (* Word String. *)π st_Word[ord(st_Word[0])] :=π chr(po_Buffer^[wo_BufferIndex]);ππ (* Advance the data-buffer index. *)π inc(wo_BufferIndex)ππ endπ Until (po_Buffer^[wo_BufferIndex] < 97)π or (po_Buffer^[wo_BufferIndex] > 122)π or (wo_BufferIndex > wo_ReadIndex);ππ (* Pack bits 0,1,2 of each Character in "letter-check" *)π (* Variable, to store Variable as 10 Char data. This *)π (* reduces memory storage requirements by 16 Bytes For *)π (* each anagram-Word, and makes data faster to sort. *)π PackBits(byar_LtrChk, rcar_Table[wo_TableIndex]^.ar_LtrChk);ππ Until (wo_BufferIndex > wo_ReadIndex);ππ (* Check if the Array of anagram-Words in the "table" *)π (* Array are sorted. If not then sort them. *)π if not TableSorted(rcar_Table, 1, wo_TableIndex) thenπ QuickSort(poar_Generic(rcar_Table), 1, wo_TableIndex, AlphaSort);ππ (* Record the position of all the anagram-Words on the *)π (* "table" Array. This will be used as a faster sorting *)π (* index. *)π For wo_Index := 1 to wo_TableIndex doπ rcar_Table[wo_Index]^.wo_Pos := wo_Index;ππ (* end of PART 5 of 7 *)π (* Start of PART 6 of 7 *)ππ (* QuickSort the "table" of anagram Words, using Sort1 *)π (* routine. *)π QuickSort(poar_Generic(rcar_Table), 1, wo_TableIndex, Sort1);ππ (* Attempt to open a File to Write sorted data to. *)π assign(fi_Temp, 'SORTED.DAT');π {$I-}π reWrite(fi_Temp, 1);ππ (* Check For I/O errors. *)π CheckIOerror;ππ (* Set the temporary String to ', ' + Cr + Lf. *)π st_Temp := ', ' + #13#10;ππ (* Reset the loop index. *)π wo_Index := 1;ππ (* Repeat...Until all anagram-Word on "table" Array are *)π (* processed. *)π Repeatππ (* Reset the counter Variables. *)π by_LastAnagram := 0;π by_CurrentWord := 0;ππ (* While the next anagram-Word belongs to the same *)π (* anagram-group, advance the by_LastAnagram Variable. *)π While (rcar_Table[(wo_Index + by_LastAnagram)]^.ar_LtrChk =π rcar_Table[succ(wo_Index + by_LastAnagram)]^.ar_LtrChk) doπ inc(by_LastAnagram);ππ (* Repeat...Until next anagram-Word is not in the same *)π (* anagram group. *)π Repeatππ (* With current anagram group do... *)π With rcar_Groups[(wo_Index + by_CurrentWord)]^ doπ beginππ (* Move the first anagram-Word in "table" Array to the *)π (* current anagram group-String. *)π move(rcar_Table[(wo_Index + by_CurrentWord)]^.st_Word[1],π st_Group[1], ord(rcar_Table[(wo_Index +π by_CurrentWord)]^.st_Word[0]));ππ (* Set the length-Char of current anagram-String to 12. *)π st_Group[0] := #12;ππ (* Record the first anagram-Word position. *)π wo_Pos := rcar_Table[(wo_Index + by_CurrentWord)]^.wo_Pos;ππ (* Loop from 0 to total number of anagrams in the group *)π For by_Index := 0 to by_LastAnagram doππ (* If the loop index is not equal the the current *)π (* anagram-Word, then... *)π if (by_Index <> by_CurrentWord) thenπ beginππ (* Add the next anagram-Word to the anagram-String. *)π move(rcar_Table[(wo_Index + by_Index)]^.st_Word[1],π st_Group[succ(length(st_Group))],π ord(rcar_Table[(wo_Index +π by_Index)]^.st_Word[0]));ππ (* Record the length of the anagram-Word added to the *)π (* anagram-String. *)π inc(st_Group[0],π ord(rcar_Table[(wo_Index +π by_Index)]^.st_Word[0]));ππ (* If the current anagram-Word is not the last anagram- *)π (* Word of the anagram-group, and the loop-index is *)π (* less than the last anagram-Word, or the loop-index *)π (* is less than the 2nd to last anagram-Word in group *)π if ((by_CurrentWord <> by_LastAnagram) andπ (by_Index < by_LastAnagram))π or (by_Index < pred(by_LastAnagram)) thenπ beginππ (* end of PART 6 of 7 *)π (* Start of PART 7 of 7 *)ππ (* Add the comma and space Character to anagram-String. *)π move(st_Temp[1],π st_Group[succ(length(st_Group))], 2);π inc(st_Group[0], 2)π endπ end;ππ (* Add the CR + Lf to anagram String. *)π move(st_Temp[3], st_Group[succ(length(st_Group))], 2);π inc(st_Group[0], 2);ππ (* Advance the currrent anagram-Word index. *)π inc(by_CurrentWord)ππ endπ Until (by_CurrentWord > by_LastAnagram);ππ (* Advance the anagram-group index by the current *)π (* anagram-Word index. *)π inc(wo_Index, by_CurrentWord);ππ Until (wo_Index > wo_TableIndex);ππ (* QuickSort the anagram-Strings, using Sort2. *)π QuickSort(poar_Generic(rcar_Groups), 1, wo_TableIndex, Sort2);ππ (* Initialize loop control Variable. *)π wo_CurrentIndex := 1;ππ (* Repeat Until all the anagram Words in the "table" *)π (* Array have been processed. *)π Repeatππ (* Initialize loop control Variable. *)π wo_BufferIndex := 1;ππ (* Place all the anagram-Strings in the data-buffer. *)π While (wo_CurrentIndex <= wo_TableIndex)π and (wo_BufferIndex < co_SafeSize) doπ With rcar_Groups[wo_CurrentIndex]^ doπ beginπ (* Place current anagram-String in the data-buffer. *)π move(st_Group[1], po_Buffer^[wo_BufferIndex],π length(st_Group));ππ (* Advance the data-buffer index by length of anagram- *)π (* String. *)π inc(wo_BufferIndex, length(st_Group));ππ (* Advance current anagram-String index. *)π inc(wo_CurrentIndex)ππ end;ππ (* Write the anagram Text data in the buffer to disk. *)π blockWrite(fi_Temp, po_Buffer^[1], pred(wo_BufferIndex));ππ (* Check For I/O errors. *)π CheckIOerror;ππ Until (wo_CurrentIndex >= wo_TableIndex);ππ (* Close the sorted anagram-Text File. *)π close(fi_Temp);ππ (* Check For I/O errors. *)π CheckIOerrorππend.ππ (* end of PART 7 of 7 *)π{ Hi, to All:ππ ...I gather that the 3rd Programming contest (Anagram Word sort)π is officially over, and am now posting my entry's source-code.ππ This Program should execute in well under 1 second on a 486-33π ram-disk. (It's about 3.21 sec on my 386sx-25) The final compiledπ size of the .EXE is 7360 Bytes.ππ ...I've commented the h*ll out of my source-code, so it's a bitπ on the big side.ππ ...Here is a "quick" run-down of how it works:ππ 1- Creates a 60K buffer on the HEAP.ππ 2- Creates an Array table to store all the anagram Wordsπ and data about each Word, on the HEAP.ππ 3- Creates an Array of anagram-group Strings on the HEAP.ππ 4- Read the entire anagram-Word input File WordLIST.DATπ into the 60K buffer in 1 big chunk.ππ 5- Finds all the anagram-Words in the buffer, and assignsπ their data to the anagram-Word table on the HEAP.ππ 6- Each letter of every anagram-Word is Recorded in anπ Array of 26 Bytes. Then the first 3 bits of each ofπ the 26 Bytes is packed, so that this data can beπ stored in a 10 Character Array in each anagram-Wordπ table Record. (The bits are packed to save space andπ to make the sorting faster.) This method allows forπ a maximum of 7 of the same letter in each Word, whichπ should be sufficient For this contest.ππ 7- The table of anagram Records is then checked to see ifπ the anagram-Words are in sorted order. (In this contestπ the original input File is in sorted order.) If they areπ not in sorted order, QuickSort is called to put theπ Words (actually Pointers to the Words) in order.ππ 8- Now that the anagram-Words are in sorted order, theirπ position in the anagram-Word table is Recorded in aπ position field within each anagram-Word Record.ππ 9- The table of anagram-Word Records is now sorted usingπ a multi-key QuickSort. This will sort the anagram-Wordπ Records by:π 1- Length of anagram-Word.π 2- Letters that each anagram-Word contains.π 3- Alphabeticly.ππ ...This multi-key sort will establish the anagram groups,π and sort the members of each group alphabeticly.ππ 10- Open the sorted output File.ππ 11- Create N number of anagram-Strings from N mumber of anagram-π Words in each anagram-group. Keeping the anagram Words inπ the String in sorted order.ππ 12- QuickSort the anagram-group Strings into alphabetical order.ππ 13- Place all the sorted anagram-group Strings back into theπ 60K buffer.ππ 14- Write the entire buffer to the SORTED.DAT File, and closeπ this File.ππ NOTES: Well this is the first time I've figured out how to doπ multi-key QuickSorts, which I wasn't sure was possibleπ at first.ππ I also tried using a 32-bit CRC value to identify theπ anagram-groups which ran even faster, but should notπ be considered a "safe" method, as it's accuracy is onlyπ guaranteed For 2-7 Character Words.ππ File I/O and repetitive loops are usually the big speedπ killers in these Types of contests, so I always try toπ keep them to a minimum.ππ ...My entry could possibly be tweaked further still,π but I've got a life. <g>ππ} 3 05-28-9313:57ALL SWAG SUPPORT TEAM ANAGRAM2.PAS IMPORT 125 { ANAGRAM. --------------------------------------------------------------------π Raphaël Vanney, 01/93ππ Purpose : Reads a list of Words 4 to 10 Characters long from a Fileπ named 'LIST.#1', outputs a list of anagrams founds in aπ specified format to a File named 'ANAGRAM.RES'.ππ Note : I commented-out the source using a langage, say English, whichπ I'm not Really fluent in ; please forgive mistakes.π------------------------------------------------------------------------------}ππ{$m 8192,65536,655360}π{$a+,d+,e-,f-,g+,i+,l+,n-,o-,q-,r-,s-,v+}ππ{$b-} { Turns off complete Boolean evaluation ; this allows easiestπ combined Boolean tests. }ππUses Crt,π Objects ;ππConstπ MaxWordLen = 10 ; { Offically specified by GP ! }π CntAnagrams : Word = 0 ; { Actually, this counter shows the }π { number of Words found in the }π { output File. }π OutFileName = 'ANAGRAM.RES' ;πππType TWordString = String[MaxWordLen] ;ππ { TWordCollection.π This Object will be used to store the Words in a sorted fashion. Asπ long as the input list is already sorted, it could have inheritedπ from TCollection, put there is no big penalty using a sorted one. }ππ TWordCollection =π Object (TSortedCollection)π Function KeyOf(Item : Pointer) : Pointer ; Virtual ;π Function Compare(Key1, Key2 : Pointer) : Integer ; Virtual ;π Procedure FreeItem(Item : Pointer) ; Virtual ;π end ;π PWordCollection = ^TWordCollection ;ππ { TWord.π This is the Object we'll use to store a Word. Each Word knows :π - it's 'Textual form' : Itπ - the first of it's anagrams, if it has been found to be theπ anagram of another Word,π - the next of it's anagrams, in the same condition. }ππ PWord = ^TWord ;π TWord =π Objectπ It : TWordString ;π FirstAng : PWord ;π NextAng : PWord ;ππ Constructor Init(Var Wrd : TWordString) ;π Destructor Done ;π end ;ππVar WordsList : PWordCollection ; { The main list of Words }π OrgMem : LongInt ; { Original MemAvail }π UsedMem : LongInt ; { Amount of RAM used }ππ{-------------------------------------- TWord --------------------------------}ππConstructor TWord.Init ;πbeginπ It:=Wrd ;π FirstAng:=Nil ;π NextAng:=Nil ;πend ;ππDestructor TWord.Done ;πbeginπend ;ππ{-------------------------------------- TWordCollection ----------------------}π{ The following methods are not commented out, since they already are inπ Turbo-Pascal's documentations, and they do nothing unusual. }ππFunction TWordCollection.KeyOf ;πbeginπ KeyOf:=Addr(PWord(Item)^.It) ;πend ;ππFunction TWordCollection.Compare ;πVar k1 : PString Absolute Key1 ;π k2 : PString Absolute Key2 ;πbeginπ If k1^>k2^π Then Compare:=1π Else If k1^<k2^π Then Compare:=-1π Else Compare:=0 ;πend ;ππProcedure TWordCollection.FreeItem ;πbeginπ Dispose(PWord(Item), Done) ;πend ;ππ{-------------------------------------- Utilities ----------------------------}ππProcedure CleanUp(Var Wrd : TWordString) ;π{ Cleans-up a Word, in Case there would be dirty Characters in the input File }πVar i : Integer ;πbeginπ { Removes trailing spaces ; not afraid of empty Strings }π While Wrd[Length(Wrd)]=' ' Do Dec(Wrd[0]) ;π { Removes any suspect Character }π i:=1 ;π While (i<=Length(Wrd)) Doπ beginπ If Wrd[i]<#33 Then Delete(Wrd, i, 1)π Else Inc(i) ;π end ;πend ;ππFunction PadStr(St : TWordString ; Len : Integer) : String ;π{ Returns a String padded With spaces, of the specified length }πVar i : Integer ;π Tmp : String ;πbeginπ Tmp:=St ;π For i:=Length(Tmp)+1 To Len Do Tmp[i]:=' ' ;π Tmp[0]:=Chr(Len) ;π PadStr:=Tmp ;πend ;ππ{-----------------------------------------------------------------------------}ππFunction AreAnagrams(Var WordA, WordB : TWordString) : Boolean ;π{ Tells whether two Words are anagrams of each other ; assumes the Wordsπ are 'clean' (No Up/Low Case checking, no dirty Characters...)ππ Optimizing hint : Passing parameters by address _greatly_ enhances overallπ speed ; anyway, we'll use a local copy of one of the two, since the usedπ algorithms needs to modify one of the two Words. }ππAssembler ;πVar WordC : TWordString ; { Local copy of WordB }πAsmπ Push DS { Let's save the Data segment... }π LDS SI, WordA { Load WordA's address in ES:DI }π Mov AL, [SI] { Load length Byte into AL }π LDS SI, WordB { Load WordB's address }π Cmp AL, [SI] { Compare lengthes }π JNE @NotAng { <>lengthes, not anagrams }ππ LDS SI, WordBππ { Let's make a local copy of WordB ; enhanced version of TP's "Move" }π ClD { Clear direction flag }π Push SSπ Pop ES { Segment part of WordC's address }π LEA DI, WordC { Offset part of it }π Mov CL, DS:[SI] { Get length Byte }π XOr CH, CH { Make it a Word }π Mov DL, CL { Save length For later use }π Inc CX { # of Bytes to store the String }π ShR CX, 1 { We'll copy Words ; CF is importt }π Rep MovSW { Copy WordB to WordC }π JNC @NoByteπ MovSB { Copy last Byte }π@NoByte:π LDS SI, WordA { DS:SI contains WordA's address }π Inc SI { SI points to first Char of WordA }π Mov DH, DL { Use DH as a loop counter }π LEA BX, WordC { Load offset of WordC in BX }π Inc BX { Skip length Byte }π { For each letter in WordA, search it in WordB ; if found, mark it asπ 'used' in WordB, then proceed With next.π If a letter is not found, Words are not anagrams ; if all areπ found, Words are anagrams. }π{ Registers usage :π AL : scratch For SCASπ AH : unusedπ BX : offset part of WordC's addressπ CX : will be used as a counter For SCASπ DL : contains length of Strings ; 'll be used to reset CXπ DH : loop counter ; initially =DLπ ES : segment part of WordC's addressπ DI : scratch For SCASπ DS:SI : Pointer to next Char to process in WordAπ}π@Bcle:π LodSB { Load next Char of WordA in AL }π Mov CL, DL { Load length of String in CX }π Mov DI, BX { Copy offset of WordC to DI }π RepNE ScaSB { Scan WordC For AL 'till found }π JNE @NotAng { Char not found, not anagrams }π Dec DI { Back-up to matching Char }π Mov Byte Ptr ES:[DI], '*' { Mark the Character as 'used' }π Dec DH { Dec loop counter }π Or DH, DH { Done all Chars ? }π JNZ @Bcle { No, loop }ππ { All Chars done, the Words are anagrams }π Mov AL, 1 { Result=True }π Or AL, AL { Set accordingly the ZF }π Jmp @Doneπ@NotAng:π XOr AL, AL { Result=False }π@Done:π Pop DS { Restore DS }πend ;ππFunction ReadWordsFrom(FName : String) : Boolean ;πVar InF : Text ; { Input File }π Buf : Array[1..2048] Of Byte ; { Speed-up Text buffer }π Lig : String ; { Read line }π Wrd : String ; { Word gotten from parsed Lig }π WSt : TWordString ; { Checked version of Wrd }π p : Integer ; { Work }π Cnt : LongInt ; { Line counter }πbeginπ ReadWordsFrom:=False ; { 'till now, at least ! }π WordsList:=New(PWordCollection, Init(20, 20)) ;π Assign(InF, FName) ;π {$i-}π ReSet(InF) ;π {$i+}π If IOResult<>0 Then Exit ;π SetTextBuf(InF, Buf, SizeOf(Buf)) ;π Cnt:=0 ;ππ While Not EOF(InF) Doπ beginπ Inc(Cnt) ;π ReadLn(InF, Lig) ;π While Lig<>'' Doπ beginπ { Let's parse the read line into Words }π p:=Pos(',', Lig) ;π If p=0 Then p:=Length(Lig)+1 ;π Wrd:=Copy(Lig, 1, p-1) ;π { Check of overflowing Word length }π If Length(Wrd)>MaxWordLen Thenπ WriteLn('Word length > ', MaxWordLen, ' : ', Wrd) ;π WSt:=Wrd ;π CleanUp(WSt) ;π If WSt<>'' Then WordsList^.Insert(New(PWord, Init(WSt))) ;π Delete(Lig, 1, p) ;π end ;π end ;π {$i-}π Close(InF) ;π {$i+}π If IOResult<>0 Then ;π ReadWordsFrom:=True ;ππ WriteLn(Cnt, ' lines, ', WordsList^.Count, ' Words found.') ;πend ;ππProcedure CheckAnagrams(i : Integer) ;π{ This Procedure builds, if necessary (i.e. not already done), the anagramsπ list For Word #i of the list. }πVar Org : PWord ; { Original Word (1st of list) }π j : Integer ; { Work }π Last : PWord ; { Last anagram found }πbeginπ Org:=WordsList^.Items^[i] ;π If Org^.FirstAng<>Nil Thenπ beginπ { This Word is already known to be the anagram of at least anotherπ one ; don't re-do the job. }π { _or_ this Word is known to have no anagrams in the list }π Exit ;π end ;ππ { Search anagrams }π Last:=Org ;π Org^.FirstAng:=Org ; { This Word is the first of it's }π { own anagrams list ; normal, no ? }π For j:=Succ(i) To Pred(WordsList^.Count) Doπ { Don't search the begining of the list, of course ! }π beginπ { Let's skip anagram checking if lengths are <> }π If Org^.It[0]=PWord(WordsList^.Items^[j])^.It[0] Thenπ If AreAnagrams(Org^.It, PWord(WordsList^.Items^[j])^.It) Thenπ beginπ { Build chained list of anagrams }π Last^.NextAng:=WordsList^.Items^[j] ;π Last:=WordsList^.Items^[j] ;π Last^.FirstAng:=Org ;π end ;π end ;π Last^.NextAng:=Nil ; { Unusefull, but keep carefull }πend ;ππProcedure ScanForAnagrams ;π{ This Procedure scans the list of Words For anagrams, and do the outputingπ to the 'ANAGRAM.RES' File. }ππVar i : Integer ; { Work }π Tmp : PWord ; { Temporary Word }π Out : Text ; { Output File }π Comma : Boolean ; { Helps dealing With commas }π Current : PWord ; { Currently handled Word }πbeginπ Assign(Out, OutFileName) ;π ReWrite(Out) ;ππ With WordsList^ Doπ For i:=0 To Pred(Count) Doπ beginπ Current:=Items^[i] ;π CheckAnagrams(i) ;π { We're now gonna scan the chained list of known anagrams forπ this Word. }π If (Current^.NextAng<>Nil) Or (Current^.FirstAng<>Current) Thenπ { This Word has at least an anagram other than itself }π beginπ Write(Out, PadStr(Current^.It, 12)) ;π Inc(CntAnagrams) ;π Comma:=False ;π Tmp:=Current^.FirstAng ;π While Tmp<>Nil Doπ beginπ If Tmp<>Current Then { Don't reWrite it... }π beginπ If Comma Then Write(Out, ', ') ;π Comma:=True ;π Write(Out, Tmp^.It) ;π Inc(CntAnagrams) ;π end ;π Tmp:=Tmp^.NextAng ;π end ;π WriteLn(Out) ;π end ;π end ;ππ Close(Out) ;πend ;ππVar Tmp : LongInt ;ππbeginπ { Check command line parameter }ππ If ParamCount<>1 Thenπ beginπ WriteLn('Anagram. Raphaël Vanney, 01/93 - Anagram''s contest entry.');π WriteLn ;π WriteLn('Anagram <input_File>') ;π WriteLn ;π WriteLn('Please specify input File name.') ;π Halt(1) ;π end ;ππ OrgMem:=MemAvail ;ππ { Read Words list from input File }ππ If Not ReadWordsFrom(ParamStr(1)) Thenπ beginπ WriteLn('Error reading Words from input File.') ;π Halt(1) ;π end ;ππ { Display statistics stuff }ππ WriteLn('Reading and sorting done.') ;π UsedMem:=OrgMem-MemAvail ;π WriteLn('Used RAM : ', UsedMem, ' Bytes') ;π Tmp := Trunc(1.0 * MemAvail / (1.0 * UsedMem / WordsList^.Count)) ;π If Tmp > 16383 Thenπ Tmp := 16383 ;π WriteLn('Potential Words manageable : ', Tmp) ;ππ { Scan For anagrams, create output File }ππ ScanForAnagrams ;π WriteLn('Anagrams scanning & output done.') ;π WriteLn(CntAnagrams, ' Words written to ', OutFileName) ;ππ { Clean-up }π Dispose(WordsList, Done) ;πend.π{ππ------------------------------------------------------------------------------ππOkay, this is my entry For the 'anagram contest' !ππThe few things I'd like to point-out about it :ππ. I chosed to use OOP, in contrast to seeking speed. I wouldn't say myπ Program is Really slow (7.25 secs on my 386-33), but speed was not myπ first concern.π. It fully Uses one of the interresting points of OOP in TP, i.e.π reusability, through inheritance,π. When a Word (A) has been found to be an anagram of another (B), theπ Program never searches again For the anagrams of (A) ; thisπ highly reduces computing time... but I believe anybody does the same.π. I also quite like the assembly langage Function 'AreAnagrams'.ππ------------------------------------------------------------------------------ππThe Words list is stored in memory in the following maner :π. A collection (say, a list) of the Words,π. Within this list, anagrams are chained as a listπ. Each Word knows the first and the next of its anagramsππ------------------------------------------------------------------------------ππFor the sake of speed, I did something I'm quite ashamed of ; but itπsaves 32% of execution time, so...πThe usual way to access element #i of a TCollection is to call Function Atπwith parameter i (i.e. At(i)) ; there is also another way, which is not Reallyπclean, but which I chosed to use : access it directly through Items^[i].π 4 05-28-9313:57ALL SWAG SUPPORT TEAM BUBBLE1.PAS IMPORT 6 {π> Does anyone know of a routine or code that would allow For aπ> alphabetical sort?ππDepends on what Type of sorting you want to do- For a very small list, aπsimple BubbleSort will suffice.π}πConstπ max = 50;πVarπ i,j:Integer;π a : Array[1..max] of String;π temp : String;πbeginπ For i := 1 to 50 doπ For j := 1 to 50 doπ if a[i] < a[j] thenπ beginπ temp := a[i];π a[i] := a[j];π a[j] := temp;π end; { if }πend.ππ{πIf it's a bigger list than, say 100 or so elements, or it needs to beπsorted often, you'll probably need a better algorithm, like a shell sortπor a quicksort.π}ππ 5 05-28-9313:57ALL SWAG SUPPORT TEAM BUBBLE2.PAS IMPORT 8 {π> Does anyone know of a routine or code that would allow forπ> a alphbetical sort in pascal? If so could you mail orπ> Write it in this base? Thanks!ππI know of a couple but this is the best and fastest one that I know ofππBubble Sortπ}ππTypeπ StArray = Array [1..10] of String;ππProcedure bubble_sort(Var names : StArray);πVarπ i,π last,π latest : Integer;π temp : String;π exchanged : Boolean;πbeginπ last := max_names - 1;π Repeatπ i := 1;π exchanged := False;π latest := last;π Repeatπ if names[i] > names[i+1] thenπ beginπ temp := names[i];π names[i] := names[i+1];π names[i+1] := temp;π exchanged := True;π latest := i;π end;π inc(i);π Until not (i <= last);π last := latest;π Until not ((last >= 2) and exchanged);πend;π 6 05-28-9313:57ALL SWAG SUPPORT TEAM COMB1.PAS IMPORT 11 {π>Has anyone successfully converted the Combsort algorithm (I think it wasπ>published in DDJ or Byte about two years ago) from C to Pascal? I'veπ>lost the original C source For this, but if anyone has any info, I wouldπ>appreciate it.π}ππProgram TestCombSort; { Byte magazine, April '91 page 315ff }πConstπ Size = 25;πTypeπ SortType = Integer;πVarπ A: Array [1..size] of SortType;π i: Word;ππProcedure CombSort (Var Ain);πVarπ A: Array [1..Size] of SortType Absolute Ain;π Switch: Boolean;π i, j, Gap: Word;π Hold: SortType;πbeginπ Gap := Size;π Repeatπ Gap := Trunc (Gap / 1.3);π if Gap < 1 thenπ Gap := 1;π Switch := False;π For i := 1 to Size - Gap doπ beginπ j := i + Gap;π if A [i] > A [j] then { swap }π beginπ Hold := A [i];π A [i] := A [j];π A [j] := Hold;π Switch := True;;π end;π end;π Until (Gap = 1) and not Switch;πend;ππbeginπ Randomize;π For i := 1 to Size doπ A [i] := Random (32767);π WriteLn;π WriteLn ('Unsorted:');π For i := 1 to Size doπ Write (A [i]:8);π WriteLn;π CombSort (A);π WriteLn ('Sorted:');π For i := 1 to Size doπ Write (A [i]:8);π WriteLn;πend.π 7 05-28-9313:57ALL SWAG SUPPORT TEAM COUNT1.PAS IMPORT 16 {π ...Well, as Greg Vigneault reminded me, there is a much fasterπ method of sorting this sort of data called a "Count" sort. Iπ often overlook this method, as it doesn't appear to be a sortπ at all at first glance:π}πProgram Count_Sort_Demo;ππConstπ co_MaxItem = 200;ππTypeπ byar_MaxItem = Array[1..co_MaxItem] of Byte;π byar_256 = Array[0..255] of Byte;ππVarπ by_Index : Byte;π wo_Index : Word;π DataBuffer : byar_MaxItem;π SortTable : byar_256;ππbeginπ (* Initialize the pseudo-random number generator. *)π randomize;ππ (* Clear the CountSort table. *)π fillChar(SortTable, sizeof(SortTable), 0);ππ (* Create random Byte data. *)π For wo_Index := 1 to co_MaxItem doπ DataBuffer[wo_Index] := random(256);ππ (* Display random data. *)π Writeln;π Writeln('RANDOM Byte DATA');π For wo_Index := 1 to co_MaxItem doπ Write(DataBuffer[wo_Index]:4);ππ (* CountSort the random data. *)π For wo_Index := 1 to co_MaxItem doπ inc(SortTable[DataBuffer[wo_Index]]);ππ (* Display the CountSorted data. *)π Writeln;π Writeln('COUNTSORTED Byte DATA');π For by_Index := 0 to 255 doπ if (SortTable[by_Index] > 0) thenπ For wo_Index := 1 to SortTable[by_Index] doπ Write(by_Index:4)πend.π{π ...This Type of sort is EXTEMELY fast, even when compared toπ QuickSort, as there is so little data manipulation being done.ππ>BTW, why are there so many different sorting methods?π>Quick, bubble, Radix.. etc, etcππ ...Because, Not all data is created equally.π (ie: Some Types of sorts perform well on data that is veryπ random, While other Types of sorts perform well on dataπ that is "semi-sorted" or "almost sorted".)ππ} 8 05-28-9313:57ALL SWAG SUPPORT TEAM COUNT2.PAS IMPORT 34 {π>I'm in need of a FAST way of finding the largest and the smallestπ>30 numbers out of about 1000 different numbers.π> ...Assuming that the 1000 numbers are in random-order, I imagineπ> that the simplest (perhaps fastest too) method would be to:π> 1- Read the numbers in an Array.π> 2- QuickSort the Array.π> 3- First 30 and last 30 of Array are the numbers you want.π> ...Here's a QuickSort demo Program that should help you With theπ> sort: ...ππ Stop the presses, stop the presses!ππ Remember the recent Integer sort contest, on the Intelec Programmingπ conference? The fastest method was a "counting" sort technique, whichπ used the Integers (to be sorted) as indexes of an Array.ππ You asked John Kuhn how it worked, as his example code was in messyπ C. I sent you an explanation, along With example TP source. Aroundπ that time my link to Intelec was intermittently broken; I didn'tπ hear back from you - so you may not have received my message (datedπ Jan.02.1993). I hope you won't mind if I re-post it here and now...ππ In a message With John Kuhn...π> Simply toggle the sign bit of the values beFore sorting. Everythingπ> falls into place appropriately from there.π> ...OK, but how about toggling them back to their originalπ> state AFTER sorting? (I want to maintain negative numbers)π> How can you tell which data elements are negative numbers???ππ Hi Guy,ππ if you've got all of this under your belt, then please disregardπ the following explanation ...ππ By toggling the high bit, the Integers are changed in a way that,π conveniently, allows sorting by magnitude: from the "most negative"π to "most positive," left to right, using an Array With unsignedπ indexes numbering 0...FFFFh. The Array size represents the numberπ of all possible (16-bit) Integers... -32768 to 32767.ππ The "Count Sort" involves taking an Integer, toggling its high bitπ (whether the Integer is originally positive or negative), thenπ using this tweaked value as an index into the Array. The tweakedπ value is used only as an Array index (it becomes an unsignedπ index somewhere within 0..FFFFh, inclusive).ππ The Array elements, which are initialized to zero, are simply theπ counts of the _occurrences_ of each Integer. The original Integers,π With proper sign, are _derived_ from the indexes which point toπ non-zero elements (after the "sort")... ie. an original Integer isπ derived by toggling the high bit of a non-zero element's index.ππ Array elements of zero indicate that no Integer of the correspondingπ (derived) value was encountered, and can be ignored. if any elementπ is non-zero, its index is used to derive the original Integer. ifπ an Array element is greater than one (1), then the correspondingπ Integer occurred more than once.ππ A picture is worth 1000 Words: The following simplified exampleπ sorts some negative Integers. The entire Count Sort is done byπ a Single For-do-inC() loop - hence its speed. The xors do theπ required high-bit toggling ...π}πππProgram DemoCountSort; { Turbo Pascal Count Sort. G.Vigneault }ππ{ some negative Integers to sort ... }πConstπ SomeNegs : Array [0..20] of Integer =π (-2,-18,-18,-20000,-100,-10,-8,-11,-5,π -1300,-17,-1,-16000,-4,-12,-15,-19,-1,π -31234,-6,-7000 );ππ{ pick an Array to acComplish Count Sort ... }πVarπ NegNumArray : Array [$0000..$7FFF] of Byte;π{ PosNumArray : Array [$8000..$FFFF] of Byte; }π{ AllNumArray : Array [$0000..$FFFF] of Byte; use heap }π Index : Word;π IntCount : Byte;ππbeginπ { Initialize }π FillChar( NegNumArray, Sizeof(NegNumArray), 0 );ππ { Count Sort (the inC does this) ... }ππ For Index := 0 to 20 doπ { Just 21 negative Integers to sort }π inC( NegNumArray[ Word(SomeNegs[Index] xor $8000) ]);ππ { then display the sorted Integers ... }π For Index := 0 to $7FFF doπ { Check each Array element }π For IntCount:= 1 to NegNumArray[Index] doπ { For multiples }π WriteLn( Integer(Index xor $8000) ); { derive value }ππend { DemoCountSort }.π 9 05-28-9313:57ALL SWAG SUPPORT TEAM ELEVATR1.PAS IMPORT 15 {π> Thanks For the code... It worked great! BTW, why are there so manyπ> different sorting methods? Quick, bubble, Radix.. etc, etcππYes, there are lots of sorting algorithms out there! I also found this outπthe hard way! :-) A couple of years ago, I only knew the so-called "bubble"πsort, and decided to create my own sorting algorithm. It would have to beπfaster than bubble, yet remaining small, simple, and not memory hungry.πand I did it, but only to find out a few weeks later that there were muchπbetter sorts than the one I created... But it sure was great fun beatingπbubble! (which is brain-dead anyway! ;-)ππSo here it is, my two cents to the history of sorting algorithms, theπamazing, blazingly fast (*)... ELEVAtoR SorT!... Why ELEVAtoR??, you ask inπunison! Because it keeps going up & down! :-)π}ππProgram mysort;ππUses Crt;ππConstπ max = 1000;ππTypeπ list = Array[1..max] of Word;ππVarπ data : list;π dummy : Word;πππProcedure elevatorsort(Var a: list; hi: Word);ππVarπ lo,π peak,π temp,π temp2 : Word;ππbeginπ peak := 1;π lo := 1;π Repeatπ temp := a[lo];π temp2 := a[lo + 1];π if temp > temp2 thenπ beginπ a[lo] := temp2;π a[lo + 1] := temp;π if lo <> 1 then dec(lo);π endπ elseπ beginπ inc(peak);π lo:=peak;π end;π Until lo = hi;πend;πππbeginπ ClrScr;π Writeln('Generating ', max ,' random numbers...');π randomize;π For dummy:=1 to max do data[dummy]:=random(65535);π Writeln('Sorting random numbers...');π elevatorsort(data,max);π For dummy:=1 to max do Write(data[dummy]:5,' ');πend.ππ{π(*) it's speed lies somewhere between "BUBBLE" and "inSERT"; it's muchπfaster than "BUBBLE", and a little slower than "inSERT"... :-)π}π 10 05-28-9313:57ALL SWAG SUPPORT TEAM ELEVATR2.PAS IMPORT 11 {π>Why can't Borland come out With a Universal sort since they made theπ>Program.. <G>ππI guess there's no such thing as a "universal" sort... There are a few veryπgood sorting algorithms, and depending on some factors, you just have toπchoose the one that best fits your needs!ππHere's an update to my ELEVAtoR sort, this one's even faster!π}ππProgram mysort;ππUses Crt;ππConstπ max = 1000;ππTypeπ list = Array[1..max] of Word;ππVarπ data : list;π dummy : Word;πππProcedure elevatorsort(Var a: list; hi: Word);ππVarπ dummy,π low,π peak,π temp,π temp2 : Word;ππbeginπ peak := 1;π low := 1;π temp2 := a[low + 1];π Repeatπ temp := a[low];π if temp > temp2 thenπ beginπ a[low] := temp2;π a[low + 1] := temp;π if low <> 1 then dec(low);π endπ elseπ beginπ inc(peak);π low:=peak;π if low <> hi then temp2:=a[low + 1];π end;π Until low = hi;πend;ππbeginπ ClrScr;π Writeln('Generating ', max ,' random numbers...');π randomize;π For dummy:=1 to max do data[dummy]:=random(65535);π Writeln('Sorting random numbers...');π elevatorsort(data,max);π For dummy:=1 to max do Write(data[dummy]:5,' ');πend.π 11 05-28-9313:57ALL SWAG SUPPORT TEAM IMROVSRT.PAS IMPORT 20 {πMARK OUELLETππ> I code these things this way:π>π> for I := 1 to MAX-1 doπ> for J := I+1 to MAX doπ> if A[I] < A[J] thenπ> beginπ> ( swap code )π> endππ this can be improved even more. By limiting the MAX value on eachπsuccessive loop by keeping track of the highest swaped pair.ππ If on a particular loop, no swap is performed from element MAX-10πonto the end. Then the next loop does not need to go anyhigher thanπMAX-11. Remember you are moving the highest value up, if no swap isπperformed from MAX-10 on, it means all values above MAX-11 are in orderπand all values below MAX-10 are smaller than MAX-10.π}ππ{$X+}πprogram MKOSort;ππUSESπ Crt;ππConstπ MAX = 1000;ππvarπ A : Array[1..MAX] of word;π Loops : word;ππprocedure Swap(Var A1, A2 : word);πvarπ Temp : word;πbeginπ Temp := A1;π A1 := A2;π A2 := Temp;πend;ππprocedure working;πconstπ cursor : array[0..3] of char = '\|/-';π CurrentCursor : byte = 1;π Update : word = 0;πbeginπ update := (update + 1) mod 2500;π if update = 0 thenπ beginπ DirectVideo := False;π write(Cursor[CurrentCursor], #13);π CurrentCursor := ((CurrentCursor + 1) mod 4);π DirectVideo := true;π end;πend;ππprocedure Bubble;πvarπ Highest,π Limit, I : word;π NotSwaped : boolean;πbeginπ Limit := MAX;π Loops := 0;π repeatπ I := 1;π Highest := 2;π NotSwaped := true;π repeatπ working;π if A[I] > A[I + 1] thenπ beginπ Highest := I;π NotSwaped := False;π Swap(A[I], A[I + 1]);π end;π Inc(I);π until (I = Limit);π Limit := Highest;π Inc(Loops);π until (NotSwaped) or (Limit <= 2);πend;ππprocedure InitArray;πvarπ I, J : word;π Temp : word;πbeginπ randomize;π for I := 1 to MAX doπ A[I] := I;π for I := MAX - 1 downto 1 doπ beginπ J := random(I) + 1;π Swap(A[I + 1], A[J]);π end;πend;ππprocedure Pause;πbeginπ writeln;π writeln('Press any key to continue...');π while keypressed doπ readkey;π while not keypressed do;π readkey;πend;ππprocedure PrintOut;πvarπ I : word;πbeginπ ClrScr;π For I := 1 to MAX doπ beginπ if WhereY >= 22 thenπ beginπ Pause;π ClrScr;π end;π if (WhereX >= 70) thenπ Writeln(A[I] : 5)π elseπ Write(A[I] : 5);π end;π writeln;π Pause;πend;ππbeginπ ClrScr;π InitArray;π PrintOut;π Bubble;π PrintOut;π writeln;π writeln('Took ', Loops, ' Loops to complete');πend.π 12 05-28-9313:57ALL SWAG SUPPORT TEAM MODHEAP.PAS IMPORT 39 {πOk, here is your "fastest sort routine." I spent a couple hours just tweakingπand testing to make sure that it was performing 100%.ππAdding $G+ only yielded a very slight speed increase but a noticeable one. (Theπspeed results below are based on $G-.) Using anything other than Integer forπVariables caused a slight degredation in performance. I would guess thatπInteger arithmetic is where Borland focused its optimizations on. Word andπLongInt all caused performance degredation.ππAND, it used to be that previous to v6 or v5.5 that multiplication was a bottleπneck too, as in J := I * 3; The faster method was to say J := I+I+I; sinceπaddition is faster than multiplication. I didn't see any appreciable differenceπwith respect to multiplication over addition here.ππThe following algorithm is a modified Fibonacci Heap sort With the addition ofπa mid-sort bounce technique. It runs almost twice the speed of the Quick Sortπalgorithm as posted in my last message.ππIt Uses considerably less stack then Quick Sort since it is non-recursive. And,πfor those of you who hate GOTO's, there's three in this code. Any other way Iπcould think of would increase data and reduce performance. But you're certainlyπwelcome to jump in and knock 'em outa there if you can!ππHere are the speed results as tested on 386-40mhz:ππ 500 Elements - (Less than 1/10 second)π 1000 Elements - 0.1 Secondsπ 1500 Elements - 0.2 Secondsπ 2000 Elements - 0.3 Secondsπ 5000 Elements - 1.0 Secondsπ 7500 Elements - 1.7 Secondsπ 10000 Elements - 2.3 SecondsππI modified the skeleton Program slightly to increase the number of 10 CharacterπStrings to 10,000 so that I could test that far.ππHere is the source code For the algorithm. Just "Plug" it into the skeletonπProgram I posted a day or so ago.ππ{------------------------------------------------------------------------}πProcedure ModHeapSort( Total : Integer );πVarπ I,J,K,L : Integer;π X, Temp : Pointer;π M,M1,M2 : Integer;ππ Label JumpOut;π Label Terminate;π Label SmallSort;ππbeginπ if Total <= 4 Thenπ Goto SmallSort; { Too small For Split sorting }ππ M := Pred(Total) div 3;π M1 := ( M * 3 ) + 2;ππ if M1 <= Total Thenπ beginπ if M1 < Total Thenπ if SortArray[M1]^ < SortArray[Total]^ Thenπ M2 := Totalπ ELSEπ M2 := M1π ELSEπ M2 := M1;ππ if SortArray[1]^ < SortArray[M2]^ Thenπ begin { Swap first element to M2 }π Temp := SortArray[1];π SortArray[1] := SortArray[M2];π SortArray[M2] := Temp;π end;ππ end; {IF M1 <= Total}ππ For L := M DownTo 1 DOπ beginπ X := SortArray[L];π I := L;π J := I * 3;ππ Repeatππ K := Pred(J);ππ if SortArray[K]^ < SortArray[J]^ Thenπ K := J;π if SortArray[K]^ < SortArray[Succ(J)]^ Thenπ K := Succ(J);ππ SortArray[I] := SortArray[K];π I := K;π J := I * 3;ππ Until J > M1;ππ J := Succ(I) div 3;ππ Repeatππ if SortArray[J]^ >= SmallArrPtr(X)^ Thenπ Goto JumpOut;ππ SortArray[I] := SortArray[J];π I := J;π J := Succ(J) div 3;ππ Until J < L;ππ JumpOut:π SortArray[I] := X;ππ end;ππ For L := M1 To Total DOπ beginπ X := SortArray[L];π I := L;π J := Succ(I) div 3;ππ if SortArray[J]^ < SmallArrPtr(X)^ Thenπ beginππ Repeatπ SortArray[I] := SortArray[J];π I := J;π J := Succ(J) div 3;π Until SortArray[J]^ >= SmallArrPtr(X)^;ππ SortArray[I] := X;ππ end; {IF}π end; {For}ππ L := Total;ππ While L > 4 DOπ beginπ X := SortArray[L];π SortArray[L] := SortArray[1];π Dec(L,1);π I := 1;π J := 3;ππ Repeatπ K := Pred(J);ππ if SortArray[K]^ < SortArray[J]^ Thenπ K := J;π if SortArray[K]^ < SortArray[Succ(J)]^ Thenπ K := Succ(J);ππ SortArray[I] := SortArray[K];π I := K;π J := I * 3;π Until J >= L;ππ Dec(J,1);ππ if J <= L Thenπ beginπ if J < L Thenπ if SortArray[J]^ < SortArray[L]^ Thenπ J := L;π SortArray[I] := SortArray[J];π I := J;π end; {IF}ππ J := Succ(I) div 3;ππ if SortArray[J]^ < SmallArrPtr(X)^ Thenπ Repeatπ SortArray[I] := SortArray[J];π I := J;π J := Succ(J) div 3;π Until SortArray[J]^ >= SmallArrPtr(X)^;ππ SortArray[I] := X;π end;ππ { Process last four remaining elements, or less than 4 to sort }π { Use "Insertion sort" method For best linear time performance }ππ SmallSort :π if Total <= 4 Thenπ L := Totalπ ELSEπ L := 4;ππ For I := 2 To L DOπ beginπ X := SortArray[I];π For J := Pred(I) DownTo 1 DOπ if SortArray[J]^ > SmallArrPtr(X)^ Thenπ SortArray[Succ(J)] := SortArray[J]π ELSEπ Goto Terminate;π J := 0;ππ Terminate : SortArray[Succ(J)] := X;ππ end; {For I}πend;π 13 05-28-9313:57ALL SWAG SUPPORT TEAM OOP-SORT.PAS IMPORT 10 {πWL> Say, would anyone know how-to sort a Record With 5 thingπ WL> in it one of which is "NAME"...I want to sort each Recordπ WL> in the Array by name and can't figure it out....my Arrayπ WL> name is LabelS and my Record name is SofT....so any helpπ WL> would greatly be appreciated...thanksππThe easiest way is to make it an Object, and put it in a TSortedCollection.πFor example:π}ππ Typeπ PMyrec = ^TMyrec;π TMyrec = Object(tObject)π name : String;π other : Integer;π end;ππ TSortedRecs = Object(TSortedCollection)π Function Compare(Key1,key2:Pointer):Integer; Virtual;π end;ππ Function TSortedRecs.Compare;π Varπ p1 : PMyrec Absolute Key1;π p2 : PMyrec Absolute Key2;π beginπ if p1^.name < p2^.name thenπ Compare := -1π else if p1^.name = p2^.name thenπ Compare := 0π elseπ Compare := 1;π end;ππVarπ rec : PMyrec;π coll: TSortedRecs; beginπ coll.init(100,10); { Init to 100 Records, grow by 10s }ππ While More_Records doπ beginπ new(rec,init);π rec^.name := Get_Name;π rec^.other:= Get_Other;π coll.insert(rec);π end;π 14 05-28-9313:57ALL SWAG SUPPORT TEAM PNTRSORT.PAS IMPORT 28 {πREYNIR STEFANSSONππSome time ago I wangled myself into a beta testing team For a floppyπdisk catalogger called FlopiCat. This is a rather BASIC (in more than oneπway) Program, but works well enough.ππThe built-in sorting routine was a bit quacked, so I wrote my ownπexternal sorter, which is both more versatile and faster (by far) than theπinternal one.ππ Here it is, in Case someone can use the idea (and code):π}ππProgram FlopiSrt; { Sorts FlopiCat.Dat. }ππConstπ Maximum = 6000; { I don't need that many meself... }π FName : String[12] = 'Flopicat.Dat';ππTypeπ fEntry = Recordπ n : Array[1..4] of Char;π i : Array[1..35] of Char;π d : Array[1..39] of Char;π end;ππ En1 = Array[1..78] of Char;π En2 = Recordπ n : Array[1..4] of Char;π f : Array[1..9] of Char;π e : Array[1..3] of Char;π z : Array[1..8] of Char;π t : Array[1..15] of Char;π d : Array[1..39] of Char;π end;ππ En3 = Recordπ f, d : Array[1..39] of Char;π end;ππ pEntry = ^fEntry;ππVarπ Entry : Array [1..Maximum] of pEntry;π fc : File of fEntry;π Rev : Boolean;π LoMem : Pointer;π i,π NumOfEntries : Integer;π nfd : Char;π s : String;ππFunction ToSwap(i, j : Integer) : Boolean;πVarπ Swop : Boolean;πbeginπ Swop := False;π Case nfd OFπ { Sorting by disk number: }π 'N' : if Entry[i]^.n > Entry[j]^.n thenπ Swop := True;π { Sorting by File information: }π 'I' : if Entry[i]^.i > Entry[j]^.i thenπ Swop := True;π { Sorting by description: }π 'D' : if Entry[i]^.d > Entry[j]^.d thenπ Swop := True;π { Sorting by all the String: }π 'A' : if En1(Entry[i]^) > En1(Entry[j]^) thenπ Swop := True;π { Sorting by File name only: }π 'F' : if En2(Entry[i]^).f > En2(Entry[j]^).f thenπ Swop := True;π { Sorting by File extension only: }π 'E' : if En2(Entry[i]^).e > En2(Entry[j]^).e thenπ Swop := True;π { Sorting by File size: }π 'Z' : if En2(Entry[i]^).z > En2(Entry[j]^).z thenπ Swop := True;π { Sorting by date/time stamp: }π 'T' : if En2(Entry[i]^).t > En2(Entry[j]^).t thenπ Swop := True;π { Sorting by disk number/File info block: }π 'B' : if En3(Entry[i]^).f > En3(Entry[j]^).f thenπ Swop := True;π end;π ToSwap := Swop xor Rev;πend;ππ{ if I remember correctly, I settled on using shaker/shuttle sort. }πProcedure SortIt;πVarπ i, j,π pb, pf,π pp, pt : Integer;π t : pEntry;ππ Procedure SwapIt(i, j : Integer);π beginπ t := Entry[i];π Entry[i] := Entry[j];π Entry[j] := t;π end;ππbeginπ Write('0 entries processed.');π i := 0;π pt := 2;π pb := NumOfEntries;π pf := 0;π Repeatπ pp := pt;π Repeatπ if ToSwap(pp - 1, pp) thenπ beginπ SwapIt(pp - 1, pp);π pf := pp;π end;π Inc(pp);π Until pp > pb;ππ pb := pf - 1;π j := i;π i := NumOfEntries - (pb - pt + 2);π if (i MOD 10) < (j MOD 10) thenπ Write(#13, i);π if pb < pt thenπ Exit;π pp := pb;ππ Repeatπ if ToSwap(pp - 1, pp) thenπ beginπ SwapIt(pp - 1, pp);π pf := pp;π end;π Dec(pp);π Until pp < pt;ππ pt := pf + 1;π j := i;π i := NumOfEntries - (pb - pt + 2);π if (i MOD 10) < (j MOD 10) thenπ Write(#13, i);π Until pb < pt;πend;ππ 15 05-28-9313:57ALL SWAG SUPPORT TEAM QUICK1.PAS IMPORT 15 Unit Qsort;ππ{ππCopyright 1990 Trevor J CarlsenπAll rights reserved.ππAuthor: Trevor J Carlsenπ PO Box 568π Port Hedland WA 6721π πA general purpose sorting Unit.πππ}ππInterfaceππTypeπ updown = (ascending,descending);π str255 = String;π dataType = str255; { the Type of data to be sorted }π dataptr = ^dataType;π ptrArray = Array[1..10000] of dataptr;π Arrayptr = ^ptrArray;π πConst π maxsize : Word = 10000;π SortType : updown = ascending;π πProcedure QuickSort(Var da; left,right : Word);ππ{============================================================================}πImplementationπ πProcedure swap(Var a,b : dataptr); { Swap the Pointers }π Var t : dataptr;π beginπ t := a;π a := b;π b := t;π end;π π πProcedure QuickSort(Var da; left,right : Word);π Varπ d : ptrArray Absolute da;π pivot : dataType;π lower,π upper,π middle : Word;ππ beginπ lower := left;π upper := right;π middle:= (left + right) div 2;π pivot := d[middle]^;π Repeatπ Case SortType ofπ ascending : beginπ While d[lower]^ < pivot do inc(lower);π While pivot < d[upper]^ do dec(upper);π end;π descending: beginπ While d[lower]^ > pivot do inc(lower);π While pivot > d[upper]^ do dec(upper);π end;π end; { Case } π if lower <= upper then beginπ { swap the Pointers not the data }π swap(d[lower],d[upper]);π inc(lower);π dec(upper);π end;π Until lower > upper;π if left < upper then QuickSort(d,left,upper);π if lower < right then QuickSort(d,lower,right);π end; { QuickSort }ππend.πππ 16 05-28-9313:57ALL SWAG SUPPORT TEAM QUICK2.PAS IMPORT 16 {...This is as generic a QuickSort as I currently use:π}π{$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,P-,R-,S-,T-,V-}π{$M 60000,0,0}ππProgram QuickSortDemo;πUsesπ Crt;ππConstπ coMaxItem = 30000;ππTypeπ Item = Word;π arItem = Array[1..coMaxItem] of Item;ππ (***** QuickSort routine. *)π (* *)πProcedure QuickSort({update} Var arData : arItem;π {input } woLeft,π woRight : Word);πVarπ Pivot,π TempItem : Item;π woIndex1,π woIndex2 : Word;πbeginπ woIndex1 := woLeft;π woIndex2 := woRight;π Pivot := arData[(woLeft + woRight) div 2];π Repeatπ While (arData[woIndex1] < Pivot) doπ inc(woIndex1);π While (Pivot < arData[woIndex2]) doπ dec(woIndex2);π if (woIndex1 <= woIndex2) thenπ beginπ TempItem := arData[woIndex1];π arData[woIndex1] := arData[woIndex2];π arData[woIndex2] := TempItem;π inc(woIndex1);π dec(woIndex2)π endπ Until (woIndex1 > woIndex2);π if (woLeft < woIndex2) thenπ QuickSort(arData, woLeft, woIndex2);π if (woIndex1 < woRight) thenπ QuickSort(arData, woIndex1, woRight)πend; (* QuickSort. *)ππVarπ woIndex : Word;π Buffer : arItem;ππbeginπ Write('Creating ', coMaxItem, ' random numbers... ');π For woIndex := 1 to coMaxItem doπ Buffer[woIndex] := random(65535);π Writeln('Finished!');π Write('Sorting ', coMaxItem, ' random numbers... ');π QuickSort(Buffer, 1, coMaxItem);π Writeln('Finished!');π Writeln;π Writeln('Press the <ENTER> key to display all ', coMaxItem,π ' sorted numbers...');π readln;π For woIndex := 1 to coMaxItem doπ Write(Buffer[woIndex]:8)πend.π 17 05-28-9313:57ALL SWAG SUPPORT TEAM QUICK3.PAS IMPORT 13 { File that will teach me how to quick sort? I know how quick sort worksπ but I don't know why my Program doesn't sort properaly. Sometimes it goesπ through one cycle of sort and sometimes it goes through two cycles of sortπ but it never sorts it Completely! Tek ChanππHere is some generic source code, change it to suit your needs/Types:π}ππProcedure Split(Var Info: ArrayType; First: Integer; Last: Integer; VarπSplitPt1: Integer; Var SplitPt2: Integer);ππVar SplitVal, Temp: ArrayElementType;ππbeginπ SplitVal:=Info[(First+Last) div 2];π Repeatπ While Info[First] < SplitVal doπ First:=First+1;π While Info[Last] > SplitVal doπ Last:=Last-1;π if First <= Last thenπ beginπ Temp:=Info[First];π Info[First]:=Info[Last];π Info[Last]:=Temp;π First:=First+1;π Last:=Last-1;π endπ Until First > Last;π SplitPt1:=First;π SplitPt2:=Last;πend;ππProcedure QuickSort(Var Info: ArrayType; First:Integer; Last: Integer);ππVar SplitPt1, SplitPt2: Integer;ππbeginπ if First < Last thenπ beginπ Split(Info, First, Last, SplitPt1, SplitPt2);π if SplitPt1 < Lastπ then QuickSort(Info, SplitPt1, Last);π if First < SplitPt2π then QuickSort(Info, First, SplitPt2);π endπend;ππ{πThis is a -very- fast sort, much faster than any other I have. Does aπnon-recursive version exist? Are there any faster sorts? Brianπ} 18 05-28-9313:57ALL SWAG SUPPORT TEAM QUICK4.PAS IMPORT 17 Unit qsort;ππInterfaceππProcedure quicksort(Var s; left,right : Word);ππImplementationππProcedure quicksort(Var s; left,right : Word; SortType: sType);π { On the first call left should always be = to min and right = to max }π Varπ data : DataArr Absolute s;π pivotStr,π tempStr : String;π pivotLong,π tempLong : LongIntπ lower,π upper,π middle : Word;ππ Procedure swap(Var a,b);π Var x : DirRec Absolute a;π y : DirRec Absolute b;π t : DirRec;π beginπ t := x;π x := y;π y := t;π end;ππ beginπ lower := left;π upper := right;π middle:= (left + right) div 2;π Case SortType ofπ _name: pivotStr := data[middle].name;π _ext : pivotStr := data[middle].ext;π _size: pivotLong := data[middle].Lsize;π _date: pivotLong := data[middle].Ldate;π end; { Case SortType }π Repeatπ Case SortType ofπ _name: beginπ While data[lower].name < pivotStr do inc(lower);π While pivotStr < data[upper].name do dec(upper);π end;π _ext : beginπ While data[lower].ext < pivotStr do inc(lower);π While pivotStr < data[upper].ext do dec(upper);π end;π _size: beginπ While data[lower].Lsize < pivotLong do inc(lower);π While pivotLong < data[upper].Lsize do dec(upper);π end;π _date: beginπ While data[lower].Ldate < pivotLong do inc(lower);π While pivotLong < data[upper].Ldate do dec(upper);π end;π end; { Case SortType }π if lower <= upper then beginπ swap(data[lower],data[upper]);π inc(lower);π dec(upper);π end;π Until lower > upper;π if left < upper then quicksort(data,left,upper);π if lower < right then quicksort(data,lower,right);π end; { quicksort }ππππππππ 19 05-28-9313:57ALL SWAG SUPPORT TEAM QUICK5.PAS IMPORT 19 {π>I'm in need of a FAST way of finding the largest and the smallestπ>30 numbers out of about 1000 different numbers.ππ ...Assuming that the 1000 numbers are in random-order, I imagineπ that the simplest (perhaps fastest too) method would be to:ππ 1- Read the numbers in an Array.ππ 2- QuickSort the Array.ππ 3- First 30 and last 30 of Array are the numbers you want.ππ ...Here's a QuickSort demo Program that should help you With theπ sort:π}ππ{$A+,B-,D-,E-,F-,I-,L-,N-,O-,R-,S+,V-}π{$M 60000,0,0}ππProgram QuickSort_Demo;πUsesπ Crt;ππConstπ co_MaxItem = 30000;ππTypeπ Item = Word;π ar_Item = Array[1..co_MaxItem] of Item;πππ (***** QuickSort routine. *)π (* *)πProcedure QuickSort({update} Var ar_Data : ar_Item;π {input } wo_Left,π wo_Right : Word);πVarπ Pivot,π TempItem : Item;π wo_Index1,π wo_Index2 : Word;πbeginπ wo_Index1 := wo_Left;π wo_Index2 := wo_Right;π Pivot := ar_Data[(wo_Left + wo_Right) div 2];π Repeatπ While (ar_Data[wo_Index1] < Pivot) doπ inc(wo_Index1);π While (Pivot < ar_Data[wo_Index2]) doπ dec(wo_Index2);π if (wo_Index1 <= wo_Index2) thenπ beginπ TempItem := ar_Data[wo_Index1];π ar_Data[wo_Index1] := ar_Data[wo_Index2];π ar_Data[wo_Index2] := TempItem;π inc(wo_Index1);π dec(wo_Index2)π endπ Until (wo_Index1 > wo_Index2);π if (wo_Left < wo_Index2) thenπ QuickSort(ar_Data, wo_Left, wo_Index2);π if (wo_Index1 < wo_Right) thenπ QuickSort(ar_Data, wo_Index1, wo_Right)πend; (* QuickSort. *)ππVarπ wo_Index : Word;π ar_Buffer : ar_Item;ππbeginπ Write('Creating ', co_MaxItem, ' random numbers... ');π For wo_Index := 1 to co_MaxItem doπ ar_Buffer[wo_Index] := random(65535);π Writeln('Finished!');π Write('Sorting ', co_MaxItem, ' random numbers... ');π QuickSort(ar_Buffer, 1, co_MaxItem);π Writeln('Finished!');π Writeln;π Writeln('Press the <ENTER> key to display all ', co_MaxItem,π ' sorted numbers...');π readln;π For wo_Index := 1 to co_MaxItem doπ Write(ar_Buffer[wo_Index]:8)πend.π 20 05-28-9313:57ALL SWAG SUPPORT TEAM RADIX1.PAS IMPORT 34 {π Here's my solution to your "contest". The first I'm rather proudπ of, it incorporates bAsm to beat your devilshly efficient CASEπ Implementation by a factor of 2x.ππ The second, I am rather disappointed With as it doesn't even comeπ CLOSE to TP's inbuilt STR Function. (The reason, I have found, isπ because TP's implementaion Uses a table based approach that wouldπ be hard to duplicate With Variable radixes. I am working on aπ Variable radix table now)πππ ****************************************************************π Converts String pointed to by S into unsigned Integer V. Noπ range or error checking is performed. Caller is responsible forπ ensuring that Radix is in proper range of 2-36, and that noπ invalid Characters exist in the String.π ****************************************************************π}πTypeπ pChar = ^chr_Array;π chr_Array = Array[0..255] of Char;π Byte_arry = Array[Char] of Byte;ππConstπ sym_tab : Byte_arry = (π 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,π 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,π 0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,π 0,0,0,0,0,0,0,10,11,12,13,14,15,16,17,π 18,19,20,21,22,23,24,25,26,27,28,29,30,π 31,32,33,34,35,0,0,0,0,0,0,10,11,12,13,π 14,15,16,17,18,19,20,21,22,23,24,25,26,π 27,28,29,30,31,32,33,34,35,0,0,0,0,0,0,π 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,π 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,π 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,π 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,π 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,π 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,π 0,0,0,0,0,0,0,0,0,0,0,0,0π );ππProcedure RadixVal(Var V:LongInt; S:PChar;Radix:Byte);πVarπ digit :Byte;π p, p2 :Pointer;π hiwd, lowd :Word;πbeginπ V := 0;π p := @S^[0];π p2 := @V;π Asmπ les bx, p2π push dsπ pop esπ lds si, pπ @loop3:π lea di, [sym_tab]π xor ah, ahπ lodsbπ cmp al, 0π je @quitπ add di, ax { index to Char position in table }π mov al, Byte PTR [di]π mov digit, alπ xor ah, ahπ mov al, Radixπ mov cx, axπ mul Word PTR [bx]π mov lowd, axπ mov hiwd, dxπ mov ax, cxπ mul Word PTR [bx+2] { mutliply high Word With radix }π add hiwd, ax { add result to previous result - assume hi result 0 }π mov ax, lowdπ mov dx, hiwdπ add al, digit { add digit value }π adc ah, 0 { resolve any carry }π mov [bx], ax { store final values }π mov [bx+2], dxπ jmp @loop3π @quit:π end;πend;ππ{π ****************************************************************π Convert unsigned Integer in V to String pointed to by S.π Radix determines the base to use in the conversion. No rangeπ checking is performed, the caller is responsible For ensuringπ the radix is in the proper range (2-36), and that V is positive.π ****************************************************************π}πTypeπ Char_arry = Array[0..35] of Char;ππConstπ symbols :Char_arry = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';ππProcedure RadixStr(V:LongInt; S:PChar; Radix:Byte);πVarπ digit, c :Byte;π ts :String;π p, p2 :Pointer;πbeginπ c := 255;π ts[255] := #0;π p := @V;π p2 := @ts[0];π Asmπ push dsπ lea si, [symbols]π les bx, pπ les di, p2π add di, 255π stdπ xor cx, cxπ mov cl, Radixπ @loop:π SEGES mov ax, Word PTR [bx]π SEGES mov dx, Word PTR [bx+2]π div cxπ SEGES mov Word PTR [bx], axπ SEGES mov Word PTR [bx+2], 0π mov digit, dlπ push siπ xor ah, ahπ mov al, digitπ add si, axπ movsbπ pop siπ dec cπ SEGES cmp Word PTR [bx], 0π je @doneπ SEGES cmp Word PTR [bx+2], 0π je @loopπ @done:π pop dsπ end;π ts[c] := Chr(255-c);π p := @S^[0];π Asmπ push dsπ cldπ lds si, p2π les di, pπ xor bx, bxπ mov bl, cπ add si, bxπ mov cx, 256π sub cl, cπ sbb ch, 0π rep movsbπ pop dsπ end;πend;π 21 05-28-9313:57ALL SWAG SUPPORT TEAM RADIX2.PAS IMPORT 16 {>...Assuming that the 1000 numbers are in random-order, I imagineπ> that the simplest (perhaps fastest too) method would be to:π> 1- Read the numbers in an Array.π> 2- QuickSort the Array.π> 3- First 30 and last 30 of Array are the numbers you want.ππ>Stop the presses, stop the presses!ππ <grin>ππ>Remember the recent Integer sort contest, on the Intelecπ>Programming conference?ππ ...Ah, yes... I always tend to Forget about that method.π Yes, a "count" sort would definitely be the fastest methodπ of sorting random numerical data.π ...What I had a few troubles figuring out from that postπ in the Intelec confrence, wasn't the "count sort" method,π but rather the "radix sort" or "digital sort" method,π where specific bits within each data element are usedπ to sort the data.ππ ...Here's the algorithm listed in Robert Sedgewick'sπ "Algorithms" book, published by Addison-Wesley Publishingπ Company, ISBN 0-201-06673-4 :π}ππProcedure RadixExchange(l, r, b:Integer);πVarπ t, i, j : Integer;πbeginπ if (r > l) and (b >= 0) thenπ beginπ i := l;π j := r;π Repeatπ While (bits(a[i], b, 1) = 0) and (i < j) doπ i := I + 1;π While (bits(a[j], b, 1) = 1) and (i < j) doπ j := j - j;π t := a[i];π a[i] := a;π a[j] := t;π Until (j = i);π if bits(a[r], b, 1) = 0 thenπ j := j + 1;π RadixExchange(l, (j - 1), b - 1);π RadixExchange(j, r, (b - 1));π end;πend;ππ{π>By toggling the high bit, the Integers are changed in a way that,π>conveniently, allows sorting by magnitude: from the "most negative"π>to "most positive," left to right, using an Array With unsignedπ>indexes numbering 0...FFFFh.ππ ...Why bother With the bit toggling at all? Why not just defineπ the Array's range as being: Array[-32768..32767] of Byte;π}ππ 22 05-28-9313:57ALL SWAG SUPPORT TEAM RADIXQUE.PAS IMPORT 16 Turbo Pascal Optimization Contest # 51.ππNo tangible prizes, just some bragging rights, and a brain workout.ππAssignment: Write conversion routines similar to VAL and STR that canπ handle a radix (base) of any number. For example, below isπ a straight Pascal Procedure to convert a String of any baseπ to a LongInt. Can you improve the speed of this routine,π and Write a correspondingly fast routine to convert from aπ LongInt to a String of any base?ππRules: No rules. BAsm is allowed, as long as the Functions areπ readily Compilable without the use of TAsm.ππJudging: Code will be tested on a 386-40 on March 10th, by beingπ placed into a loop With no output, like this:ππ StartTiming;π For Loop := 1 to 10000000 { ten million } doπ { Execute the test, no output }π WriteLn(StopTiming);ππReady, set, code! Here's the sample...ππ(* This Function converts an ASCIIZ String S in base Radix to LongInt Iπ * With no verification of radix validity. The calling Programmer isπ * responsible For insuring that the radix range is 2 through 36. Theπ * calling Programmer is also responsible For insuring that the passedπ * String contains only valid digits in the specified Radix. No checkingπ * is done on the individual digits of a given String. For bases 11-36π * the letters 'A'-'Z' represent the corresponding values.π *)ππProcedure StrtoLong(Var I : LongInt; S : PChar; Radix : Integer);π beginπ I := 0;π While S[0] <> #0 doπ beginπ Case S[0] of '0'..'9' : I := I * Radix + (ord(S[0])-48);π 'A'..'Z' : I := I * Radix + (ord(S[0])-54);π 'a'..'z' : I := I * Radix + (ord(S[0])-86);π Inc(s);π end;π end;ππ 23 05-28-9313:57ALL SWAG SUPPORT TEAM RADIXSRT.PAS IMPORT 24 {π> I agree... unFortunately the Radix algorithm (which is aπ> sophisticated modification of a Distribution Sort algorithm) isπ> very Complex, highly CPU dependent and highly data dependent.ππWe must be speaking of a different Radix Sort. Is the sort you areπtalking about sort numbers on the basis of their digits?ππ> My understanding is that a Radix sort cannot be implemented inπ> Pascal without using a majority of Asm (which means you might asπ> well code the whole thing in Asm.)ππ> assembly) or dig up some working code, I would love to play With it!ππ************************************************************************π* *π* Name : Joy Mukherjee *π* Date : Mar. 26, 1990 *π* Description : This is the Radix sort implemented in Pascal *π* *π************************************************************************π}ππProgram SortStuff;ππUses Crt, Dos;ππTypeπ AType = Array [1..400] of Integer;π Ptr = ^Node;π Node = Recordπ Info : Integer;π Link : Ptr;π end;π LType = Array [0..9] of Ptr;ππVarπ Ran : AType;π MaxData : Integer;ππProcedure ReadData (Var A : AType; Var MaxData : Integer);ππVar I : Integer;ππbeginπ MaxData := 400;π For I := 1 to 400 do A [I] := Random (9999);πend;ππProcedure WriteArray (A : AType; MaxData : Integer);ππVar I : Integer;ππbeginπ For I := 1 to MaxData doπ Write (A [I] : 5);π Writeln;πend;ππProcedure Insert (Var L : LType; Number, LN : Integer);ππVarπ P, Q : Ptr;ππbeginπ New (P);π P^.Info := Number;π P^.Link := Nil;π Q := L [LN];π if Q = Nil thenπ L [LN] := Pπ elseπ beginπ While Q^.Link <> Nil doπ Q := Q^.Link;π Q^.Link := P;π end;πend;πππProcedure Refill (Var A : AType; Var L : LType);πVarπ I, J : Integer;π P : Ptr;πbeginπ J := 1;π For I := 0 to 9 doπ beginπ P := L [I];π While P <> Nil doπ beginπ A [J] := P^.Info;π P := P^.Link;π J := J + 1;π end;π end;π For I := 0 to 9 doπ L [I] := Nil;πend;ππProcedure RadixSort (Var A : AType; MaxData : Integer);πVarπ L : LType;π I,π divisor,π ListNo,π Number : Integer;πbeginπ For I := 0 to 9 do L [I] := Nil;π divisor := 1;π While divisor <= 1000 doπ beginπ I := 1;π While I <= MaxData doπ beginπ Number := A [I];π ListNo := Number div divisor MOD 10;π Insert (L, Number, ListNo);π I := I + 1;π end;π Refill (A, L);π divisor := 10 * divisor;π end;πend;ππbeginπ ReadData (Ran, MaxData);π Writeln ('Unsorted : ');π WriteArray (Ran, MaxData);π RadixSort (Ran, MaxData);π Writeln ('Sorted : ');π WriteArray (Ran, MaxData);πend.π 24 05-28-9313:57ALL SWAG SUPPORT TEAM SHELL1.PAS IMPORT 14 { Arrrggghh. I hate Bubble sorts. Why don't you use Merge sort? It's a hellπ of a lot faster and if you have a large enough stack, there wouldn't beπ any problems. if you were not interested in doing a recursive sort, thenπ here is an example fo the Shell sort which is one of the most efficientπ non recursive sorts around.π}πππConstπ Max = 50;πTypeπ ArrayType = Array[1..Max] of Integer;ππVarπ Data, Temp : ArrayType;π Response : Char;π X, Iteration : Integer;ππProcedure ShellSort (Var Data : ArrayType;Var Iteration : Integer;π NumberItems : Integer);ππProcedure Sort (Var Data : ArrayType; Var Iteration : Integer;π NumberItems, Distance : Integer);ππVarπ X, Y : Integer;ππbegin {Sort}π Iteration := 0;π For Y := Distance + 1 to NumberItems Doπ begin {For}π X := Y - Distance;π While X > 0 Doπ begin {While}π if Data[X+Distance] < Data[X] thenπ begin {if}π Switch (Data[X+Distance], Data[X], Iteration);π X := X - Distance;π Iteration := Iteration + 1π end {if}π elseπ X := 0;π end; {While}π end {For}πend; {Sort}ππbegin {ShellSort}π Distance := NumberItems div 2;π While Distance > 0 doπ begin {While}π Sort (Data, Iteration, NumberItems, Distance);π Distance := Distance div 2π end; {While}πend; {ShellSort}π 25 05-28-9313:57ALL SWAG SUPPORT TEAM SOMESORT.PAS IMPORT 18 { Author: Brian Pape. }ππConstπ maxrange = 5000;ππTypeπ ListRange = 1..MaxRange;π list = Array[ListRange] of Integer;ππVarπ a,b: list;π i: Integer;ππProcedure BubbleSort(Var B : list; Terms : Integer);πVarπ J, Temp : Integer;π Changed : Boolean;π Last,π LastSwitch : Integer;πbeginπ changed := True;π Last := Terms-1;π While Changed doπ beginπ changed := False;π For J := 1 to Last doπ If B[J] > B[J+1] thenπ beginπ Temp := B[J];π B[J] := B[J+1];π B[J+1] := Temp;π Changed := True;π LastSwitch := j;π end; { If B[J] }π Last := LastSwitch -1;π end { While Changed }πend; { BubbleSort }ππProcedure Min_MaxSort(Var a : list; NumberTerms : ListRange);πVarπ temp,π i,l,r,π min,max,π tempMin,π tempMax,π indexMin,π indexMax,π s1,s2,s3,s4 : Integer;π changed : Boolean;πbeginπ l := 1; r := NumberTerms; max := MaxInt;π Repeatπ min := max;π changed := False;π max := 0;π For i := l to r doπ beginπ if a[i] > max thenπ beginπ changed := True;π Max := a[i];π indexMax := i;π end; { if }π if a[i] < min thenπ beginπ changed := True;π Min := a[i];π indexMin := i;π end; { if }π end; { For }ππ tempMin := a[indexMin];π tempMax := a[indexMax];π a[indexMax] := a[l];π a[l] := tempMin;π a[indexMin] := a[r];π a[r] := tempMax;π inc(l); dec(r);π Until (l>=r) or not changed;πend; { Min_MaxSort }πππProcedure ShellSort(Var a : list; NumberTerms : ListRange);πConstπ start = 1;π increment = 3; { division factor of terms }πVarπ i,j : ListRange;π t : Integer;π found : Boolean;πbeginπ i := start + increment;π While i <= NumberTerms doπ beginπ if a[i] < a[i - increment] thenπ beginπ j := 1;π t := a[i];π Repeatπ j := j - increment;π a[j + increment] := a[j];π if j = 1 thenπ found := Trueπ elseπ found := a[j - increment] <= t;π Until found;π a[j] := t;π end; { if }π i := i + increment;π end; { While }πend; { ShellSort }π 26 05-28-9313:57ALL SWAG SUPPORT TEAM SORT-DLL.PAS IMPORT 25 {π> Now, I gotta work on sortin' em. I believe I can 'swap' theπ> positions of the Pointers eh?π>π> I can't figure out how to swap the Pointers. Could you pleaseπ> gimme a wee bit more help? I've just started doing sorts, andπ> have only used the Bubble sort at the moment in a few Programs,π> so I'm still a little shakey on sorts. I understand the Bubbleππ Here's an *example* on how to sort a linked list. There are moreπ efficient ways to sort a list, but this gives you all theπ essential elements in doing a sort. (note that ListPtr is a doublyπ linked list)π}ππProcedure SortList(Var FCL:ListPtr);πVarπ TempAnchor, TemPtr1, TemPtr2 :ListPtr;ππ Procedure MoveLink(Var Anchor, Ptr1, Ptr2 :ListPtr);π Varπ TemPtr3, TemPtr4 :ListPtr;π beginπ TemPtr3 := Ptr1^.Next; { temporary Pointer preserves oldπ Pointer value }π TemPtr4 := Ptr2^.Last; { ditto }ππ Ptr2^.Last := Ptr1; { do the Pointer swap }π Ptr1^.Next := Ptr2;ππ Ptr1^.Last^.Next := TemPtr3; { fixup secondary Pointers }π TemPtr3^.Last := Ptr1^.Last;π Ptr1^.Last := TemPtr4;ππ if TemPtr4 <> NIL then { if temporary Pointer is notπ NIL, then it has to point toπ swapped Pointer }π TemPtr4^.Next := Ptr1;ππ if Ptr1^.Last = NIL then { if swapped Pointer points toπ preceding NIL Pointer, thisπ Pointer is the new root. }π Anchor := Ptr1;π end;ππbeginπ TempAnchor := FCL; { holds root of list during sort }π TemPtr2 := TempAnchor; { TemPtr2 points to current data beingπ Compared }π Repeatπ TemPtr1 := TemPtr2; { TemPtr1 points to the next orderedπ data }π FCL := TemPtr2; { start FCL at root of UNSorTED list -π sorted data precede this Pointer }π Repeatπ FCL := FCL^.Next;π if FCL^.data < TemPtr1^.data then { Compare data values }π TemPtr1 := FCL; { if necessary, reset TemPtr1 toπ point to the new ordered value }π Until FCL^.Next = NIL; { keep going Until you reach theπ end of the list. After Exit,π the next value in order will beπ pointed to by TemPtr1 }π if TemPtr1<>TemPtr2 then { if TemPtr1 changed, a valueπ was found out of order }π MoveLink(TempAnchor,TemPtr1,TemPtr2) { then swap Pointers }π elseπ TemPtr2 := TemPtr2^.Next; { else advance to the nextπ Pointer in list }π Until TemPtr2^.Next = NIL; { Until we are finished sortingπ the list }π FCL := TempAnchor; { changes root Pointer to new root value }πend;ππ 27 05-28-9313:57ALL SWAG SUPPORT TEAM SORT-LL.PAS IMPORT 25 {π> I have a linked list structure that I would like to sort in one ofπ> four different ways. I can sort Arrays using QuickSort, etc., but have noπ> experience sorting linked lists. Does anyone have any source codeπ> (preferably) or any suggestions on how to proceed? Any help would beπ> appreciated.ππI got Modula-2 code I wrote about one year ago. I post an excerpt fromπthe Implementation MODULE. It should be no problem to convert it toπPascal, since the languages are rather similar.π}πProcedure LISTSort(Var List : LISTType;π Ascending: Boolean);ππVarπ Last : NodeTypePtr;π Result: LISTCompareResultType;ππ Procedure TailIns( Rec : NodeTypePtr;π Var First: NodeTypePtr;π Var Last : NodeTypePtr);ππ beginπ if (First=NIL) then First := Rec else Last^.Next := Rec end;π Last := Recπ end TailIns;ππ Procedure MergeLists( a: NodeTypePtr;π b: NodeTypePtr): NodeTypePtr;ππ Varπ First: NodeTypePtr;π Last : NodeTypePtr;π Help : NodeTypePtr;ππ beginπ First := NIL;π While (b#NIL) doπ if (a=NIL) thenπ a := b; b := NILπ elseπ if (Classes[List^.ClassID].Cmp(b^.DataPtr,a^.DataPtr)=Result)π thenπ Help := a; a := a^.Nextπ elseπ Help := b; b := b^.Nextπ end;π Help^.Next := NIL;π TailIns(Help,First,Last)π endπ end;π TailIns(a,First,Last);π RETURN(First)π end MergeLists;ππ Procedure MergeSort(Var Root: NodeTypePtr;π N : CARDinAL): NodeTypePtr;ππ Varπ Help: NodeTypePtr;π a,b : NodeTypePtr;ππ beginπ if (Root=NIL) thenπ RETURN(NIL)π ELSif (N>1) thenπ a := MergeSort(Root,N div 2);π b := MergeSort(Root,(N+1) div 2);π RETURN(MergeLists(a,b))π elseπ Help := Root;π Root := Root^.Next;π Help^.Next := NIL;π RETURN(Help)π endπ end MergeSort;ππbeginπ if (List^.N<2) then RETURN end;π if (Ascending) then Result := LISTGreater else Result := LISTLess end;π List^.top^.Next := MergeSort(List^.top^.Next,List^.N);π Last := List^.top;π List^.Cursor := List^.top^.Next;π While (List^.Cursor#NIL) doπ List^.Cursor^.Prev := Last;π Last := List^.Cursor;π List^.Cursor := List^.Cursor^.Nextπ end;π Last^.Next := List^.Bottom;π List^.Bottom^.Prev := Last;π List^.CurPos := 1;π List^.Cursor := List^.top^.Nextπend LISTSort;ππ{πThe basic data structure is defined as follows:π}ππConstπ MaxClasses = 256;ππTypeπ NodeTypePtr = Pointer to NodeType;ππ NodeType = Recordπ Prev : NodeTypePtr;π Next : NodeTypePtr;π DataPtr: ADDRESSπ end;ππ LISTType = Pointer to ListType;ππ ListType = Recordπ top : NodeTypePtr;π Bottom : NodeTypePtr;π Cursor : NodeTypePtr;π N : CARDinAL;π CurPos : CARDinAL;π ClassID: CARDinALπ end;ππ ClassType = Recordπ Cmp : LISTCompareProcType;π Bytes: CARDinALπ end;ππVarπ Classes: Array [0..MaxClasses-1] of ClassType;π 28 05-28-9313:57ALL SWAG SUPPORT TEAM SORT-PTR.PAS IMPORT 11 {π This is using the concept of a PoINter Array (an Array of PoINters). Itπallows For a _very_ large amount of data, sINce you allocate each Record spaceπof the Heap. You must allocate each space For each Record as you create theπRecord:π}ππ New (INFOSTUFF[3]); { allocates space For 3rd Record }π With INFOSTUFF[6]^ do { works With 6th Record }π beginπ NAME := 'Patrick Edwards'; IDNUM := 60000; MOM := ''π end;ππ The sort could be:ππVar T : INFO;πProcedure L_HSorT (LEFT,RIGHT : Word); { Lo-Hi QuickSort }πVar LOWER,UPPER,MIDDLE : Word;π PIVOT : INFO;πbeginπ LOWER := LEFT; UPPER := RIGHT; MIDDLE := (LEFT+RIGHT) div 2;π PIVOT := INFOSTUFF[MIDDLE]^;π Repeatπ While INFOSTUFF[LOWER]^.NAME < PIVOT.NAME do INc(LOWER);π While PIVOT.NAME < INFOSTUFF[UPPER]^.NAME do Dec(UPPER);π if LOWER <= UPPER thenπ beginπ T := INFOSTUFF[LOWER]^; INFOSTUFF[LOWER]^ := INFOSTUFF[UPPER]^;π INFOSTUFF[UPPER]^ := T;π INc (LOWER); Dec (UPPER);π end;π Until LOWER > UPPER;π if LEFT < UPPER then L_HSorT (LEFT, UPPER);π if LOWER < RIGHT then L_HSorT (LOWER, RIGHT);πend; { L_HSorT }ππ{ called as:ππL_HSorT (1,10);π}π 29 05-28-9313:57ALL SWAG SUPPORT TEAM SORT-STR.PAS IMPORT 7 {πIt gets better and better. The Procedure below is incredibly fast in theπsorting of the Strings in the Arrays! 1.2 sec For 1485 Strings.π}ππProcedure Sort(item : PFilearr; Last : Integer);πVarπ i, j : Integer;π span : Integer;πbeginπ item^[0] := newstr(' ');π span := Last shr 1; {Span=Last/2}π While span > 0 doπ beginπ For i := Span to Last - 1 doπ beginπ For j := (i - Span + 1) downto 1 doπ if item^[j]^ <= item^[j + Span]^ thenπ j:=1 {to make it quit the j-loop}π elseπ begin {swap Array(j) With Array(j+Span)}π item^[0] := item^[j];π item^[j] := item^[j + Span];π item^[j + Span] := item^[0];π end;π end;π Span := Span shr 1; {Span=Span/2}π end;πend;π 30 05-28-9313:57ALL SWAG SUPPORT TEAM SORTFAST.PAS IMPORT 21 {π> I might share With you a sorting Procedure which I developed Forπ> 'those Arrays we were talking about:π> ...π> Exeperimentally I used it on 1485 Strings, which took about 3 secπ> on my 386DX40. Could you advise on some method to do it evenπ> faster?ππI'll share With you a little sort routine which I use often in my Programsπwhenever I need a fast and efficient routine With very low overhead... It Usesπconsiderably less code than your example, and should outperForm it. (It wouldπbe even faster if it was all coded in Assembly!-- hint hint DJ) :-)π}ππProcedure Sort_It( totalItems : Word );ππ Function Is_Less( TemPtr1, TemPtr2 : Pointer ) : Boolean;π beginπ Is_Less := ( YourStruct(TemPtr1^).Item < YourStruct(TemPtr2^).Item );π end;ππVarπ I,J : Word;π Cur : Word;ππbeginπ For I := 1 to Pred(totalItems) doπ beginπ Cur := I;ππ For J := I + 1 to totalItems doπ if Is_Less( Item[J], Item[Cur] ) thenπ ExchangeLongInts( LongInt(Item[J]), LongInt(Item[Cur]) );π end; { For }ππend; { Proc }ππ{πThere's a couple things I should explain: The "ExchangeLongInts" Procedure isπfrom the TurboPower Opro's OpInline Unit. All it does is exchange two LongIntπTypes without you having to use a temporary Variable. It's fast and convenient,πbut not the only possible solution here. (I'm Typecasting the Pointer into aπLongInt For a 4-Byte swap.)ππ"totalItems" is the total number of items in your Array to sort.ππ"Item" is the actual Array; Item : Array[1..xx] of Pointer_to_Record;ππ"YourStruct" used in the "Is_Less" Function is Typecasting the actual structureπor Record that "Item" is referring to. It's the only portion of the code whichπlooks at your actual data. to reverse the sort order, simply change the "<" toπ">". to change what is being sorted, just change the ".Item" to something elseπlike ".Name" or ".Zip" or whatever else might be contained in your structure.ππThis routine is simple, has a minimum amount of code, Uses very little stack,πworks only With Pointers and you are only sorting memory addresses; it neverπactually move any of your physical data. (if you did, then it would be slow.)ππIt'll sort several thousand items in only a couple seconds even on slowerπmachines, and is super on small volume runs. I would imagine that it wouldπ(90 min left), (H)elp, More? start loosing steam around 1,000 to 2,000 items, but For me, it's the bestπchoice when memory is at a premium and the Arrays are fairly small.π}ππ 31 05-28-9313:57ALL SWAG SUPPORT TEAM TIMESORT.PAS IMPORT 69 {I wrote a small Program to bench both sort routines we posted. It was anπinteresting test, however it did raise a couple questions For me, which I'llπget to in a moment. (The following Program can be used as a skeleton For tryingπother sort routines too.)ππNeedless to say, the routine you posted was dramatically faster than the one Iπposted, even though both routines are non-recursive simple sorts.ππThe maximum efficient load of the routine you posted appears to be about 3000πelements. After that, additonal elements add time exponentially. For example,πit will sort 3000 elements in 5.1 seconds, but 5000 elements takes almost 16πseconds. The sort I posted became un-benchable [bearable] at about 3000πelements when it took over a minute to Complete. I didn't test it beyond thisπpoint.ππHere are the results from my 386 33Mhz machine-- your algorithm.ππ 500 Elements - 0.1 Secondsπ 1000 Elements - 0.8 Secondsπ 1500 Elements - 1.4 Secondsπ 2000 Elements - 2.6 Secondsπ 3000 Elements - 5.1 Seconds <- Peak efficiency reachedπ 5000 Elements - 15.8 SecondsππHere is the Program I used to benchmark with. I made it so that you couldπ"tweak" portions of the sort and re-run the Program.ππIncidentally, I also Compiled this Program under Stony Brook's Pascal Plus andπwas suprised to find that it ran substantially slower. All optimizations on.ππRange Checking ($R+) exactly Doubled the time it took to sort.ππChanging "Span+1" to Succ(Span) and "total-1" to Pred(total) made the routineπabout 3% faster. However the routine then neglected to sort that last twoπelements. Adding "Inc(total,2)" solved the problem but I'm not sure why. I didπnot expect this behavior. Perhaps someone could explain why?ππI added a temporary Pointer Variable to your routine in place of the "NewStr('π... ')" code you used to simplify it.ππand one last thing... Using OPRO's OpInline Function calledπ"ExchangeLongInts()" to do the swapping instead of using a temporary Varπincreased speed another 2% (Evident at > 2000 elements.) However I did notπinclude this so that anyone interested could Compile and run this without extraπUnits.π}ππ{$A+,B-,D-,E-,F-,G-,I+,L+,N-,O-,P-,Q+,R-,S+,T-,V-,X-,Y+}π{$M 32768,0,655360}ππProgram Sort_Test; { Sorting Benchmark Using P. Beeftink's Algorithm }ππTypeπ SmallArrPtr = ^SmallArr;π SmallArr = Array[1..10] of Char; { Skip String & Length Byte }ππ TTimeString = String[20];πππVarπ SortArray : Array[1..5000] of SmallArrPtr; { A LARGE Array }ππ TickCount : LongInt Absolute $0040:$006C;π { TickCount : LongInt VOLATILE Absolute $0040:$006C; } { For Pascal+ }π Tstart,π Ttime : LongInt;ππ{------------------------------------------------------------------------}πProcedure StartTiming;πbeginπ TStart := TickCount;ππ {start at the beginning of a tick!}π Repeat Until TStart <> TickCount;ππ TStart := TickCount;ππend;π{------------------------------------------------------------------------}πProcedure StopTiming;πbeginπ TTime := TickCount - TStart;πend;π{------------------------------------------------------------------------}πFunction Elapsed : TTimeString;πVar Temp : TTimeString;π Sec10 : LongInt;πbeginππ Sec10 := TTime * 2470 div 4497;π Str( Sec10 : 4, Temp );ππ if Temp[1] = ' ' then Temp[1] := '0';ππ Inc( Temp[0] );π Temp[ Length(Temp) ] := Temp[ Pred( Length( Temp ) ) ];π Temp[ Pred( length( Temp ) ) ] := '.';ππ Elapsed := Temp;πend;π{------------------------------------------------------------------------}πProcedure MakeRandomStrings( NumtoMake : Word );πVar RNum,π I,S : Word;π Temp : String;πbeginππ Temp := '';π Temp[0] := Chr( 10 );π Randomize;ππ For I := 1 to NumtoMake doπ beginππ For S := 1 to 10 do { Create Random Strings 10 Chars in length }π beginπ RNum := Random(26);π Temp[S] := Chr( RNum + 65 );π end;ππ Move( Temp[1], SortArray[I]^, 10 );ππ end;ππend; { Proc }π{------------------------------------------------------------------------}πProcedure KDSort( total : Word );π {-My simple sort routine as posted in Pascal Echo }π { With 2 slight modifications }πVarπ i,j,π Current : Word;π TempPtr : Pointer;πbeginππ For I := 1 to total doπ beginππ Current := I;ππ For J := Succ(I) to total doπ beginπ if SortArray[J]^ < SortArray[Current]^ thenπ beginπ TempPtr := SortArray[j];π SortArray[j] := SortArray[Current];π SortArray[Current] := TempPtr;π end; {if}π end; {For}ππ end; {For}ππend;π{------------------------------------------------------------------------}πProcedure PBSort(total : Integer);π {-Peter Beeftink's Sort as Posted in Pascal Echo }π { Also With slight modifications }πVarπ I,j : Integer;π Span : Integer;π TempPtr : Pointer;πbeginππ Inc(total,2); { Required to Compensate For PRED and SUCC ? }ππ Span := total SHR $01;ππ While Span > 0 doπ beginππ For I := Span to Pred(total) {total-1} doπ beginππ For j := (I - Succ(Span) {Span+1} ) Downto 1 doπ if (SortArray[j]^ <= SortArray[j+Span]^) then j := 1 elseπ beginπ TempPtr := SortArray[j];π SortArray[j] := SortArray[j+Span];π SortArray[j+Span] := TempPtr;π end;ππ end; {For}ππ Span := Span SHR $01; { This does help speed over Span div 2! }ππ end; {WhIle}ππend;π{------------------------------------------------------------------------}πProcedure Do_Sorting( SortAmount : Word );πbeginππ MakeRandomStrings(SortAmount);ππ Write('Sorting... ');ππ StartTiming;ππ PBSort(SortAmount); { Change to KDSort() to bench second sort routine }ππ StopTiming;ππ WriteLn(SortAmount:5,' Elements - ',Elapsed,' Seconds');ππend;π{------------------------------------------------------------------------}πVar C : Word;ππbeginππ if MaxAvail < 5000 * Sizeof(SmallArr) then Halt; { not enough memory! }ππ For C := 1 to 5000 do { pre-allocate up front }π GetMem(SortArray[C],Sizeof(SmallArr));πππ Do_Sorting( 500 ); { Add more Do_Sorting()'s For whatever count }π Do_Sorting( 1000 ); { you wish to test with. }π Do_Sorting( 1500 );π Do_Sorting( 2000 );π Do_Sorting( 3000 );π Do_Sorting( 5000 );πππ { Un-comment the following if you wish to see the sorted output }ππ {π For C := 1 to 5000 do { Change 5000 to the amount you sorted }π WriteLn( SortArray[C]^ );πππ For C := 1 to 5000 doπ FreeMem(SortArray[C],Sizeof(SmallArr));ππend.π{πI plugged in a QuickSort algorithm in the "skeleton" Program in my previousπmessage to test perFormance. Here are the results:ππ 500 Elements - 0.1 Secondsπ 1000 Elements - 0.2 Secondsπ 1500 Elements - 0.4 Secondsπ 2000 Elements - 0.6 Secondsπ 3000 Elements - 0.9 Secondsπ 5000 Elements - 1.8 SecondsππVery fast indeed. I modified the algorithm to sort only by Pointers, andπoptimized a couple spots. Again, a slight speed increase is noted using OPRO'sπExchangeLongInts() in leu of using temporary Variables in 1 spot. if you haveπOPRO, replace them and you reduce the number of instructions by 2 perπiteration.ππThis is a split-list recursive sort. Works by making a pass through the entireπArray first and moves all "small" data to the left, and all "Large" data to theπright. then it sorts each half seperately.ππTake the following code segment and "plug" it into the skeleton in my previousπmessage. then change the "PBSort(SortAmount)" to "QuickSort(SortAmount)" to runπthe tests.ππHere is the code segment:ππ{------------------------------------------------------------------------}πProcedure QuickSort( total : Integer );π {------------------------------------------}π Procedure recQuickSort( L, R : Integer );π Var K,I,J : Integer;π T,π Temp : Pointer;ππ beginππ if L < R thenπ beginπ T := SortArray[L];π I := Pred(L);π J := L;π K := Succ(R);ππ While Succ(J) < K doπ if SortArray[Succ(J)]^ < SmallArrPtr(T)^ thenπ beginπ Inc(I,1);π Inc(J,1);π SortArray[I] := SortArray[J];π SortArray[j] := T;π end {if}π elseπ if SortArray[Succ(J)]^ > SmallArrPtr(T)^ thenπ beginπ Dec(K,1);π Temp := SortArray[K];π SortArray[K] := SortArray[Succ(J)];π SortArray[Succ(J)] := Temp;π end {if}π elseπ Inc(J,1);ππ recQuickSort(L,I);π recQuickSort(K,R);ππ end; { if L < R }ππ end; { Proc recQuickSort }π {------------------------------------------}ππbeginππ recQuickSort(1,total);ππend;{QuickSort}π{------------------------------------------------------------------------}π